[crash 分析] android.view.WindowManager$BadTokenException: Unable to add window

本文分析了一个Android应用在更新版本后遇到的crash问题,具体表现为`android.view.WindowManager$BadTokenException`,原因是尝试在已销毁的View上显示AlertDialog。作者通过测试复现了问题,并提出解决方案:在展示Dialog前检查View是否已被销毁,以避免此类错误。总结中强调,创建AlertDialog时需确保其依赖的Context有效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【背景介绍】

  最近项目版本更新,上线后的版本出现了这样一例crash,具体的堆栈信息如下:

android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@c5e3e83 is not valid; is your activity running?
                      at android.view.ViewRootImpl.setView(ViewRootImpl.java:584)
                      at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:282)
                      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:90)
                      at android.app.Dialog.show(Dialog.java:298)
                      at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:918)
                      at com.baidu.testalertdialogcrash.MainActivity$1$1.run(MainActivity.java:26)
                      at android.os.Handler.handleCallback(Handler.java:739)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:135)
                      at android.app.ActivityThread.main(ActivityThread.java:5386)
                      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:927)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:722)

【问题分析】

  出现上述crash,从信息提示里可以看出:在AlertDialog的show前,对应的View已经被销毁,所以想在销毁的view上展示AlertDialog肯定会发生此类的crash.为了重现这个问题,编写了如下测试代码:


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn = (Button) findViewById(R.id.test_crash);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();

                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        new AlertDialog.Builder(MainActivity.this).show();
                    }
                }, 2000);
            }
        });
    }
}

  通过测试发现,点击测试按钮后,销毁了对应的activity,此时延迟2s展示的alertDialog发生crash,完全验证了我们的猜测。知道了问题的原因,解决方法就十分简单了,在展示dialog前,判断对应的view是否已经被销毁即可。具体做法如下:

new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        // 在这里增加逻辑保护,如果view已经被销毁,就不再显示对应的AlertDialog,避免发生crash
                        if (MainActivity.this.isFinishing()) {
                            return;
                        }
                        new AlertDialog.Builder(MainActivity.this).show();
                    }
                }, 2000);

【个人总结】

  1. AlertDialog 创建依赖于View的context,在展示这个AlertDialog前,需要增加view是否被销毁的判断处理

【原创声明】

  转载请注明出处,个人Blog主页:个人博客地址
  Blog地址:http://blog.youkuaiyun.com/csdn_lexli/article

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值