android.view.WindowManager$BadTo

作者: 爱情小傻蛋 | 来源:发表于2016-10-20 11:28 被阅读9565次

    此文包含android.view.WindowManager$BadTokenException的4种情形:


    • 1.Unable to add window --token null is not valid; is your activity running

    • **2.Unable to add window --token null is not for an application **

    • 3.Unable to add window -- token android.os.BinderProxy@XXX is not valid;
      is your activity running

    • **4.Unable to add window -- token android.app.LocalActivityManager
      $LocalActivityRecord @xxx is not valid; is your activity running
      **


    情形1.android.view.WindowManager$BadTokenException: Unable to add window --token null is not valid; is your activity running?异常处理。
    $BadTokenException: Unable to add window -- 
    token null is not valid; is your activity running 
    
    E/AndroidRuntime(1412): at android.view.ViewRootImpl.setView(ViewRootImpl.java:538) 
    ......
    

    该异常多见于Popup Window组件的使用中抛出。

    原因:错误在PopupWindow.showAtLocation(findViewById(R.id.main), Gravity.BOTTOM,0,0); popwindow必须依附于某一个view,而在oncreate中view还没有加载完毕,必须要等activity的生命周期函数全部执行完毕,你需要依附的view加载好后才可以执行popwindow。

    解决办法:showAtLocation()函数可以这样改:

    //修正后代码
    findviewById(R.id.mView).post(new Runnable() {
                            @Override
                            public void run() {
                                    popwindow.showAtLocation(mView, Gravity.CENTER, 0, 0);
    
                            }
                    });
    

    总结: PopupWindow必须在某个事件中显示或者是开启一个新线程去调用,不能直接在onCreate方法中显示一个Popupwindow,否则永远会有以上的错误。

    参考
    http://stackoverflow.com/questions/4187673/problems-creating-a-popup-window-in-android-activity

    情形2.android.view.WindowManager$BadTokenException: Unable to add window --token null is not for an application ?异常处理。
    $BadTokenException: Unable to add window -- 
    token null is not for an application 
    
    E/AndroidRuntime(1412): at android.view.ViewRootImpl.setView(ViewRootImpl.java:538) 
    ......
    

    该异常多见于AlertDialog组件的使用中抛出。

    //抛异常代码
    new AlertDialog.Builder(getApplicationContext())  //不能用getApplicationContext()
                .setIcon(android.R.drawable.ic_dialog_alert)  
                .setTitle("Warnning")  
                .setPositiveButton("Yes", positiveListener)
                .setNegativeButton(  "No", negativeListener)
                .create().show(); 
    

    原因:导致报这个错是在于new AlertDialog.Builder(mcontext),虽然这里的参数是AlertDialog.Builder(Context context),但我们不能使用getApplicationContext()获得的Context,而必须使用Activity,因为只有一个Activity才能添加一个窗体。

    解决方法:将new AlertDialog.Builder(Context context)中的参数用Activity.this(Activity是你的Activity的名称)或者getActivity()来填充就可以正确的创建一个Dialog了。

    //修正后代码
    new AlertDialog.Builder(this)  //this可以替换为MainActivity.this或getActivity()
                .setIcon(android.R.drawable.ic_dialog_alert)  
                .setTitle("Warnning")  
                .setPositiveButton("Yes", positiveListener)
                .setNegativeButton(  "No", negativeListener)
                .create().show(); 
    

    参考
    http://stackoverflow.com/questions/20779377/android-custom-dialog-gives-an-error

    情形3.android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@XXX is not valid; is your activity running?异常处理。
    android.view.WindowManager$BadTokenException: Unable to add window -- 
    token android.os.BinderProxy@4250d6d8 is not valid; is your activity running?
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:698)
       
        ......
        at dalvik.system.NativeStart.main(Native Method)
    

    原因:从错误信息我们也可以明白其原因,此问题根本原因就是由于将要弹出的dialog所要依附的View已经不存在导致的。当界面销毁后再弹出来;或者界面跳转时我们的view发生改变,dialog依附的context发生变化或者界面未运行了。

    解决方法:界面已经销毁引起的错误就只能判断界面是否存在然后再弹出了。

    //修正后代码
    if(!isFinishing()) {
         alert.show();
     }
    

    参考
    http://stackoverflow.com/questions/25554279/unable-to-add-window-token-android-os-binderproxy4250d6d8-is-not-valid-is-your

    https://github.com/VKCOM/vk-android-sdk/issues/21

    情形4.android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord @xxx is not valid; is your activity running? 异常处理。
    android.view.WindowManager$BadTokenException: Unable to add window -- 
    token android.app.LocalActivityManager$LocalActivityRecord@43e5b158
    is not valid; is your activity running?  
    
    //异常代码
    TipDialog dialog = new TipDialog(XXX.this) ;
    

    原因:因为new对话框的时候,参数context 指定成了this,即指向当前子Activity的context。但子Activity是动态创建的,不能保证一直存在。其父Activity的context是稳定存在的,所以有下面的解决办法。

    解决方法:将context替换为getParent()即可。 注意:要创建dialog对象,上下文环境必须是activity,同时若ActivityGroup中嵌套ActivityGroup,嵌套多少就该使用多少个getParent()。

    //修正后代码,只有最多一个parent的情形
    TipDialog dialog = new TipDialog(getParent()) ; 
    
    //修正后代码,适用于一个或多个parent的情形
    Activity activity = TestActivity.this;  
    while (activity.getParent() != null) {  
        activity = activity.getParent();  
     }  
                  
    TipDialog dialog = new TipDialog(activity) ;                   
    

    参考
    http://stackoverflow.com/questions/9914195/webview-in-activity-group-crashing-on-dialogs

    注:为什么要使用getParent我们可以从ActivityGroup的内部机制来理解:

    TabActivity的父类是ActivityGroup,而ActivityGroup的父类是Activity。因此从Ams的角度来看,ActivityGroup与普通的Activity没有什么区别,其生命周期包括标准的start,stop,resume,destroy等,而且系统中只允许同时允许一个ActivityGroup.但ActivityGroup内部有一个重要成员变量,其类型为LocalActivityManager,该类的最大特点在于它可以访问应用进程的主类,即ActivityThread类。Ams要启动某个Activity或者赞同某个Activity都是通过ActivityThread类执行的,而LocalActivityManager类就意味着可以通过它来装载不同的Activity,并控制Activity的不同的状态。注意,这里是装载,而不是启动,这点很重要。所谓的启动,一般是指会创建一个进程(如果所在的应用经常还不存在)运行该Activity,而装载仅仅是指把该Activity作为一个普通类进行加载,并创建一个该类的对象而已,而该类的任何函数都没有被运行。装载Activity对象的过程对AmS来讲是完全不可见的,那些嵌入的Activity仅仅贡献了自己所包含的Window窗口而已。而子Activity的不同状态是通过moveToState来处理的。

    所以子Activity不是像普通的Activity一样,它只是提供Window而已,所以在创建Dialog时就应该使用getParent获取ActivityGroup真正的Activity,才可以加Dialog加入Activity中。

    相关文章

      网友评论

      • oO百味Oo:大神,这个怎么解,已经判断了 是否为null的情况,郁闷了
        android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@e66665b -- another window of type 2019 already exists
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:803)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:359)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
        at com.android.systemui.statusbar.phone.NavigationBarFragment.create(NavigationBarFragment.java:689)
        at com.android.systemui.statusbar.phone.StatusBar.createNavigationBar(StatusBar.java:1298)
        at com.android.systemui.statusbar.phone.StatusBar.showNavigationBar(StatusBar.java:2207)
        at com.android.systemui.statusbar.phone.StatusBar$20.onChange(StatusBar.java:5971)
        at android.database.ContentObserver.onChange(ContentObserver.java:130)
        at android.database.ContentObserver.onChange(ContentObserver.java:145)
        at android.database.ContentObserver$NotificationRunnable.run(ContentObserver.java:216)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6523)
      • 前行者2012:解决了我的问题。
      • 5a326a13d4dd:Toast的bug吧
      • D13954:android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@17e03bab is not valid; is your activity running?
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:617)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:300)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
        at android.app.Dialog.show(Dialog.java:319)
        at android.app.AlertDialog$Builder.show(AlertDialog.java:993)
        at android.webkit.JsDialogHelper.showDialog(JsDialogHelper.java:128)
        at com.android.webview.chromium.WebViewContentsClientAdapter.showDefaultJsDialog(WebViewContentsClientAdapter.java:439)
        at com.android.webview.chromium.WebViewContentsClientAdapter.handleJsConfirm(WebViewContentsClientAdapter.java:407)
        at org.chromium.android_webview.AwContentsClientBridge$$Lambda$3.run(Unknown Source)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:159)
        at android.app.ActivityThread.main(ActivityThread.java:5461)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)

        这种情况下又是甚么鬼,我的ac中并没有dialog,pop。这ac只是承载了一个webview,显示一些内容。
        Jinbeen:https://github.com/drakeet/ToastCompat 听说可以解决?
      • LeonXtp:第四种情形,无法用parent解决,获取parent都是null
      • jamin_it:遇到第一种情况, 感谢 :grin:
      • bitman:不知道为什么 情形1我进行了这样的处理后 甚至代码放在onResume里面调用 都还是出现这样的crash
        bitman:findViewById(R.id.root_layout).postDelayed(new Runnable() {
        @Override
        public void run() {
        if (!isFinishing()) {
        mPopUpWindow.showAtLocation(findViewById(R.id.root_layout), Gravity.CENTER,0, 0);
        }
        }, 1000};
        bitman:@爱情小傻蛋
        android.view.WindowManager$BadTokenException
        Unable to add window -- token null is not valid; is your activity running?
        1 android.view.ViewRootImpl.setView(ViewRootImpl.java:532)
        2 android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:259)
        3 android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
        4 android.widget.PopupWindow.invokePopup(PopupWindow.java:1019)
        5 android.widget.PopupWindow.showAtLocation(PopupWindow.java:850)
        6 android.widget.PopupWindow.showAtLocation(PopupWindow.java:814)
        爱情小傻蛋:@bitman 代码和崩溃贴出来看看?
      • 大帅铁:非常全而且说的很清晰

      本文标题:android.view.WindowManager$BadTo

      本文链接:https://www.haomeiwen.com/subject/nadfuttx.html