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 ActivityFragmentView,连同它的 UI 可以随时消失。因此,记住 在UI 消失时从处理程序中取消该runnable。也就是说,activity 的 onStop() 和片段的 onDestroyView() 以及自定义视图的 onDetachedFromWindow()

另外:

更好的检查是:

if (getActivity() != null && isAdded() && !getActivity().isFinishing() && mSpinner != null) {
  // do stuff
}