android.view.WindowManager显示 PopOver 时出现 $BadTokenException
android.view.WindowManager$BadTokenException while showing PopOver
我添加了以下代码以在我的微调器视图上显示弹出框。该代码使用扩展 PopupWindow 的自定义 PopOver :
@Override
public void onStart() {
super.onStart();
new Handler().postDelayed(new Runnable() {
public void run() {
if (mActivity == null || !isAdded() || mActivity.isFinishing() || mSpinner == null) {
return;
}
displayPopOver();
}
}, 500L); // have seen BadTokenException if we try to show the popup too early
}
private void displayPopOver() {
//PopOver is a custom class that extends PopupWindow
PopOver p = PopOver.createVerticalPopOver(mActivity, PopOver.Type.TIP);
p.show(mSpinner);
}
我无法重现崩溃,但通过崩溃报告我看到应用程序多次崩溃。我究竟做错了什么?在 onResume() 而不是 onStart() 中调用此代码会有帮助吗?
android.view.WindowManager$BadTokenException: Unable to add window --
token null is not valid; is your activity running?
1 at android.view.ViewRootImpl.setView(ViewRootImpl.java:532)
2 at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:259)
3 at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
4 at android.widget.PopupWindow.invokePopup(PopupWindow.java:1019)
5 at android.widget.PopupWindow.showAtLocation(PopupWindow.java:850)
6 at android.widget.PopupWindow.showAtLocation(PopupWindow.java:814)
7 at com.PopOver.show(PopOver.java:339)
8 at com.MainFragment.displayPopOver(MainFragment.java:515)
9 at com.MainFragment.access00(MainFragment.java:73)
10 at com.MainFragment.run(MainFragment.java:497)
11 at android.os.Handler.handleCallback(Handler.java:733)
12 at android.os.Handler.dispatchMessage(Handler.java:95)
13 at android.os.Looper.loop(Looper.java:136)
14 at android.app.ActivityThread.main(ActivityThread.java:5001)
15 at java.lang.reflect.Method.invokeNative(Native Method)
16 at java.lang.reflect.Method.invoke(Method.java:515)
17 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
18 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
19 at dalvik.system.NativeStart.main(Native Method)
抛出的异常表明您即将显示自定义 PopupWindow
。
虽然 500 ms
延迟可能会缓解某些设备上的问题,但这并不是解决方案。您会注意到,如果您延迟说 1000 ms
,问题很可能会永远消失。这又是不是解决方案。
为了保证,采用以下方法:
让 activity 告诉您何时可以显示您的 PopupWindow
。在您的情况下,您可以在找到 Spinner
:
后立即进行设置
mSpinner = (Spinner) findViewById(R.id.spinner);
接下来,post一个Runnable
到它:
mSpinner.post(new Runnable() {
public void run() {
displayPopOver();
}
});
这里不需要延迟。
首先:
mActivity
确保您没有保留 activity 参考资料。有更简单的方法,即 getActivity()
片段。如果您的片段已分离,它将自动 return null
。当片段处于分离状态时,isAdded()
自动 return 为 false。因此,停止持有额外的 Activity 引用或片段状态变量,它们不会自动更新。
然后:
当您安排一个应该用 UI 做某事的可运行对象时,请记住 android Activity
、Fragment
或 View
,连同它的 UI 可以随时消失。因此,记住 在UI 消失时从处理程序中取消该runnable。也就是说,activity 的 onStop()
和片段的 onDestroyView()
以及自定义视图的 onDetachedFromWindow()
。
另外:
更好的检查是:
if (getActivity() != null && isAdded() && !getActivity().isFinishing() && mSpinner != null) {
// do stuff
}
我添加了以下代码以在我的微调器视图上显示弹出框。该代码使用扩展 PopupWindow 的自定义 PopOver :
@Override
public void onStart() {
super.onStart();
new Handler().postDelayed(new Runnable() {
public void run() {
if (mActivity == null || !isAdded() || mActivity.isFinishing() || mSpinner == null) {
return;
}
displayPopOver();
}
}, 500L); // have seen BadTokenException if we try to show the popup too early
}
private void displayPopOver() {
//PopOver is a custom class that extends PopupWindow
PopOver p = PopOver.createVerticalPopOver(mActivity, PopOver.Type.TIP);
p.show(mSpinner);
}
我无法重现崩溃,但通过崩溃报告我看到应用程序多次崩溃。我究竟做错了什么?在 onResume() 而不是 onStart() 中调用此代码会有帮助吗?
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? 1 at android.view.ViewRootImpl.setView(ViewRootImpl.java:532) 2 at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:259) 3 at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69) 4 at android.widget.PopupWindow.invokePopup(PopupWindow.java:1019) 5 at android.widget.PopupWindow.showAtLocation(PopupWindow.java:850) 6 at android.widget.PopupWindow.showAtLocation(PopupWindow.java:814) 7 at com.PopOver.show(PopOver.java:339) 8 at com.MainFragment.displayPopOver(MainFragment.java:515) 9 at com.MainFragment.access00(MainFragment.java:73) 10 at com.MainFragment.run(MainFragment.java:497) 11 at android.os.Handler.handleCallback(Handler.java:733) 12 at android.os.Handler.dispatchMessage(Handler.java:95) 13 at android.os.Looper.loop(Looper.java:136) 14 at android.app.ActivityThread.main(ActivityThread.java:5001) 15 at java.lang.reflect.Method.invokeNative(Native Method) 16 at java.lang.reflect.Method.invoke(Method.java:515) 17 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) 18 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) 19 at dalvik.system.NativeStart.main(Native Method)
抛出的异常表明您即将显示自定义 PopupWindow
。
虽然 500 ms
延迟可能会缓解某些设备上的问题,但这并不是解决方案。您会注意到,如果您延迟说 1000 ms
,问题很可能会永远消失。这又是不是解决方案。
为了保证,采用以下方法:
让 activity 告诉您何时可以显示您的 PopupWindow
。在您的情况下,您可以在找到 Spinner
:
mSpinner = (Spinner) findViewById(R.id.spinner);
接下来,post一个Runnable
到它:
mSpinner.post(new Runnable() {
public void run() {
displayPopOver();
}
});
这里不需要延迟。
首先:
mActivity
确保您没有保留 activity 参考资料。有更简单的方法,即 getActivity()
片段。如果您的片段已分离,它将自动 return null
。当片段处于分离状态时,isAdded()
自动 return 为 false。因此,停止持有额外的 Activity 引用或片段状态变量,它们不会自动更新。
然后:
当您安排一个应该用 UI 做某事的可运行对象时,请记住 android Activity
、Fragment
或 View
,连同它的 UI 可以随时消失。因此,记住 在UI 消失时从处理程序中取消该runnable。也就是说,activity 的 onStop()
和片段的 onDestroyView()
以及自定义视图的 onDetachedFromWindow()
。
另外:
更好的检查是:
if (getActivity() != null && isAdded() && !getActivity().isFinishing() && mSpinner != null) {
// do stuff
}