android 崩溃打开新窗口,popupwindow-在Android活动中创建弹出窗口时出现问题

popupwindow-在Android活动中创建弹出窗口时出现问题

我正在尝试创建一个仅在应用程序首次启动时出现的弹出窗口。 我希望它显示一些文本并有一个按钮来关闭弹出窗口。 但是,我无法使PopupWindow正常工作。 我尝试了两种不同的方法:

首先,我有一个XML文件,该文件声明了弹出窗口的布局,称为popup.xml(线性布局内的textview),并将其添加到主Activity的OnCreate()中:

PopupWindow pw = new PopupWindow(findViewById(R.id.popup), 100, 100, true);

pw.showAtLocation(findViewById(R.id.main), Gravity.CENTER, 0, 0);

其次,我对这段代码进行了完全相同的操作:

final LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

PopupWindow pw = new PopupWindow(inflater.inflate(R.layout.popup, (ViewGroup) findViewById(R.layout.main) ), 100, 100, true);

pw.showAtLocation(findViewById(R.id.main_page_layout), Gravity.CENTER, 0, 0);

第一个抛出NullPointerException,第二个抛出BadTokenException并说“无法添加窗口-令牌null无效”

我到底在做什么错? 我是新手,请耐心等待。

14个解决方案

176 votes

为了避免BadTokenException,您需要推迟显示弹出窗口,直到调用所有生命周期方法之后(显示->活动窗口):

findViewById(R.id.main_page_layout).post(new Runnable() {

public void run() {

pw.showAtLocation(findViewById(R.id.main_page_layout), Gravity.CENTER, 0, 0);

}

});

kordzik answered 2020-01-06T01:08:48Z

30 votes

如果您连续启动2个活动,则Kordzik提供的解决方案将不起作用:

startActivity(ActivityWithPopup.class);

startActivity(ActivityThatShouldBeAboveTheActivivtyWithPopup.class);

如果您在这种情况下以这种方式添加弹出窗口,则会遇到相同的崩溃,因为在这种情况下ActivityWithPopup不会附加到Window。

更通用的解决方案是onAttachedToWindow和onDetachedFromWindow。

而且也不需要postDelayed(Runnable,100)。 因为这100毫不保证任何东西

@Override

public void onAttachedToWindow() {

super.onAttachedToWindow();

Log.d(TAG, "onAttachedToWindow");

showPopup();

}

@Override

public void onDetachedFromWindow() {

super.onDetachedFromWindow();

Log.d(TAG, "onDetachedFromWindow");

popup.dismiss();

}

Danylo Volokh answered 2020-01-06T01:09:22Z

17 votes

接受的答案对我不起作用。 我仍然收到BadTokenException。 因此,我只是从Handler调用了Runnable,并具有如下延迟:

new Handler().postDelayed(new Runnable() {

public void run() {

showPopup();

}

}, 100);

Todd Painton answered 2020-01-06T01:09:42Z

10 votes

使用类上下文例如。 MainActivity.this代替getApplicationContext()

bipin answered 2020-01-06T01:10:02Z

4 votes

在两种情况下可能会发生此异常。 kordzik提到了一个。 这里提到了其他场景:[http://blackriver.to/2012/08/android-annoying-exception-unable-to-add-window-is-your-activity-running/]

确保您都处理

TheMan answered 2020-01-06T01:10:26Z

4 votes

解决方案是将微调器模式设置为对话框,如下所示:

android:spinnerMode="dialog"

要么

Spinner(Context context, int mode)

tnxs RamallahDroid

看到这个。

saber answered 2020-01-06T01:10:55Z

1 votes

根据使用情况,对于要显示消息的弹出式窗口类型,使用setWindowLayoutType()将弹出式窗口类型设置为TYPE_TOAST可以避免此问题,因为这种弹出式窗口不依赖于基础活动。

编辑:副作用之一:API <= 18的弹出窗口中没有交互,因为可触摸/可聚焦事件将被系统删除。 ([http://www.jianshu.com/p/634cd056b90c])

我最终使用了TYPE_PHONE(因为该应用恰好具有SYSTEM_ALERT_WINDOW的权限,否则它也将无法使用)。

headuck answered 2020-01-06T01:11:24Z

1 votes

您可以检查rootview是否具有令牌。 您可以从活动xml mRootView获取定义的父布局。

if (mRootView != null && mRootView.getWindowToken() != null) {

popupWindow.showAtLocation();

}

Cheng answered 2020-01-06T01:11:44Z

0 votes

检查findViewById是否返回了某些内容-在构建布局之前,您可能调用得太早了

另外,您可能想发布logcat输出以获取所获取的异常

Asahi answered 2020-01-06T01:12:09Z

0 votes

您也可以尝试使用此检查:

public void showPopupProgress (){

new Handler().post(new Runnable() {

@Override

public void run() {

if (getWindow().getDecorView().getWindowVisibility() == View.GONE) {

showPopupProgress();

return;

}

popup.showAtLocation(.....);

}

});

}

Roman Nazarevych answered 2020-01-06T01:12:28Z

0 votes

如果在另一个PopupWindow中显示一个PopupWindow,请不要在第一个POP中使用该视图,而应使用原始父视图。

pop.showAtLocation(parentView, ... );

YanXing Ou answered 2020-01-06T01:12:48Z

0 votes

我在dialog.show()上使用AlertDialog遇到了相同的问题(BadTokenException)。我通过以下示例制作AlertDialog。 就我而言,该问题的原因是字符串  dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST)

我删除它后一切都正常了。

Maria answered 2020-01-06T01:13:13Z

0 votes

也许是时候使用更新的解决方案了。 如果PopupWindow的父视图具有令牌,则此方法每50毫秒检查5次。 我在自定义的PopupWindow中使用它。

private fun tryToShowTooltip(tooltipLayout: View) {

Flowable.fromCallable { parentView.windowToken != null }

.map { hasWindowToken ->

if (hasWindowToken) {

return@map hasWindowToken

}

throw RetryException()

}

.retryWhen { errors: Flowable ->

errors.zipWith(

Flowable.range(1, RETRY_COUNT),

BiFunction { error: Throwable, retryCount: Int ->

if (retryCount >= RETRY_COUNT) {

throw error

} else {

retryCount

}

})

.flatMap { retryCount: Int ->

Flowable.timer(retryCount * MIN_TIME_OUT_MS, TimeUnit.MILLISECONDS)

}

}

.onErrorReturn {

false

}

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe({ hasWindowToken ->

if (hasWindowToken && !isShowing) {

showAtLocation(tooltipLayout, Gravity.NO_GRAVITY, 100, 100)

}

}, { t: Throwable? ->

//error logging

})

}

companion object {

private const val RETRY_COUNT = 5

private const val MIN_TIME_OUT_MS = 50L

}

class RetryException : Throwable()

Camino2007 answered 2020-01-06T01:13:37Z

-1 votes

您可以通过pw.showAtLocation方法指定y偏移量来说明状态栏...

cipherz answered 2020-01-06T01:13:57Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值