Dialog and WindowManager$BadTokenException

Posted bdmh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dialog and WindowManager$BadTokenException相关的知识,希望对你有一定的参考价值。

android的开发中,Dialog的使用已经非常的频繁,在使用过程中,我们需要留意一些细节,不然就会导致诸如下面的错误发生。

android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy is not valid; is your activity running?

那今天我们就来分析一下,在开发中,导致这种错误的常见的操作。

Dialog的创建需要一个上下文Context,内部需要根据这个Context创建一个PhoneWindow。

    Dialog(@UiContext @NonNull Context context, @StyleRes int themeResId,
            boolean createContextThemeWrapper) 
        ......

        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        ......
    

当我们在一个Activity中使用Dialog时,Context通常就是所属的这个Activity对象。如果报错,也就是这个Activity上下文出现了问题。你要保证Activity是正常活动状态才行。所以我们只要知道Activity可能被破坏的原因,也就找到了BadTokenException错误发生的原因了。

异步操作:

现在一个APP已经离不开网络请求了,网络请求一般都会放到异步线程中执行,然后回调给使用者去处理界面。

当一个请求发出后,比如在Activity中发出一个HTTP请求,开发者要根据请求返回的结果去show一个Dialog,如果在没有收到请求的返回结果时,Activity被关闭了,如果没有对未接收的请求做拦截的话,那么当请求结果返回时,可能依然会触发到Activity中的回调,并执行Dialog的显示,这时Dialog的上下文已经不存在了,这时Dialog.show就会报错了。

这个原因也比较好解决,判断Context是否可用,从而取消回调操作。

单例模式

导出new Dialog,让代码凌乱,不好管理,比如微信的分享,可能很多页面都需要,那我们就需要把这个Dialog封装一下,只对外暴露简单的接口即可。

既然是一个公共类,那单例模式也是被经常用到的。如下:

public class ShareHelper 
    private static ShareHelper instance;
    private Context context;
    
    public static ShareHelper getInstance(Context context) 
        if (instance == null)
            instance = new ShareHelper();
            instance.context = context;
        
        return instance;
    

    public void ShowShareDialog() 
        ScreenBottomDialog shareDialog = new ScreenBottomDialog(context);
        shareDialog.show();
    

我们在要使用的地方通过getInstance获得ShareHelper实例对象,并使用ShowShareDialog来显示分享对话框。这个代码有问题吗?

当然不行。单例模式,对象只会被创建一次,所以instance的context对象之后赋值一次,第一次初始化时,宿主Activity对象传给了context参数,第一次使用OK。

关闭宿主Activity,再次打开这个Activity,或者在另一个Activity中继续使用这个单例对象,错误就出现了。

原因就是上下文context只保留了第一次调用者,当宿主Activity被关闭后,context其实已经不存在了,不管后面哪个Activity使用,context都不会被更新,所以报错也就理所当然了。

当然,有同学想把上面代码优化一下,改成下面这样:

public class ShareHelper 
    private static ShareHelper instance;
    ScreenBottomDialog shareDialog;
    
    public static ShareHelper getInstance() 
        if (instance == null)
            instance = new ShareHelper();
        
        return instance;
    

    public void ShowShareDialog(Context context) 
        if (shareDialog == null) 
            shareDialog = new ScreenBottomDialog(context);
        
        shareDialog.show();
    

想法不错,每次ShowShareDialog都传入一个新的context作为上下文,好像挺不错的。

但是shareDialog的空判断,导致了shareDialog的创建只会有一次,context也只会赋值一次,依然是首次使用的Activity,最终的结果上改进之前是一样的。

知道了开发中常见的导致BadTokenException错误的原因,对应着去做处理就好了,保证context为最新使用者就好了。

以上是关于Dialog and WindowManager$BadTokenException的主要内容,如果未能解决你的问题,请参考以下文章

Dialog and WindowManager$BadTokenException

android 使用activity 当dialog弹出框 ,layout出现左右两边有间距

android service可以通过windowmanager弹出对话框吗

android dialog中软键盘遮挡输入编辑框edittextt

android dialog怎么设置大小

Dialog不能设置宽高的问题