Android :BUG:WindowManager$BadTokenException

本文介绍了一种常见的Android开发问题——WindowManager$BadTokenException,并提供了详细的解决方案。问题通常发生在二次弹出自定义对话框时,解决方案涉及避免使用单例模式的工具类来管理对话框,以确保在Activity销毁时能正确清理资源。

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

我也遇到楼主同样的问题,然后百度出来的答案其实都没错,不过是方向错误,第一次加载进度框是可以的,但第二次就报这个错误,后来才发现楼主这篇文章,其实是因为工具类里面进度实例依附的activity已经销毁,应该重新创建一个,我的工具类如下: public static ProgressDialog showProgressDialog(Activity activitiy, String title, String message, DialogType dialogType) {
if (progressMap.containsKey(dialogType)) {
return progressMap.get(dialogType);
} else {
ProgressDialog progressDialog = new ProgressDialog(activitiy);
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setCancelable(false);
progressDialog.setTitle(title);
progressDialog.setMessage(message);
progressMap.put(dialogType, progressDialog);
return progressDialog;
}
}


//防止在一个activity中,map的对象一直没有释放掉,
public static void setProgressDialog(DialogType dialogType) {
progressMap.remove(dialogType);
}




Android :我的奇怪BUG:WindowManager$BadTokenException

  • BUG出现场景:在二次弹出自定义对话框的时候抛出的异常
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@406ab4c8 is not valid; is your activity running?
at android.view.ViewRoot.setView(ViewRoot.java:532)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:200)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:114)
at android.view.Window$LocalWindowManager.addView(Window.java:424)
at android.app.Dialog.show(Dialog.java:241)
at android.app.AlertDialog$Builder.show(AlertDialog.java:802)
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 这个BUG网上的解决方案真是特别的多。要么是使用getParent()代替当前的Activity.this
  • 要么是在对话框弹出之前,进行 activity.this.isFinish()判断一下。但是很不幸,这两种解决方式都不能解决我的问题。 
    • 先说第一种,使用Activity.this.getParent()。很不幸,这个方法的返回值只有在当前Activity继承自android.app.ActivityGroup才不返回null.所以,对我无效。
    • 再说第二种,看起来有道理的样子,但是我加上这个判断之后,错误依然存在,没有解决我的问题。
  • 然后我找了很久,一直没有找到我的问题的解决方式。后来无意中发现了问题出在了我的单例模式的工具类上面。 
    • 我将弹出自定义对话框的代码放进了一个单例的工具类中,以为很牛逼,很高大上。但是问题就出现在单例模式上。单例获取的对象永远是唯一对象,且final过,也就是说,App不结束,这个对象是不会被回收的。也不能手动置空。但是Activity是很脆弱的,一下就挂了。所以,正确的做法就是,在Activity销毁的时候,销毁这个对话框的工具类对象,这样就OK了。【实际上不去在销毁Activity的时候,手动置空该工具类对象也是OK的,应该是Activity在销毁的时候,会干掉自己的成员变量的吧,不清楚….】 
      正确调用方式:
public class SecondActivity extends Activity {

    private Context context;
    private List<Bean> data;
    private MydialogUtils mydialogUtils;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
        context = this;
        mydialogUtils = new MydialogUtils();
        data = new ArrayList<Bean>();
        data.add(new Bean("local system db", false));
        data.add(new Bean("local system file", true));
        data.add(new Bean("local private db", false));
        data.add(new Bean("local private file", true));
        findViewById(R.id.button1).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                mydialogUtils.showMyDialog(context, data);

            }
        });
    }

    @Override
    protected void onDestroy() {
        mydialogUtils.destoryMydialog();
//      mydialogUtils = null;
        super.onDestroy();
    }
}

   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • mydialogUtils 一定要是一个普通的对象,不要是一个单例对象,或者一个死不掉的对象。!!!! 
    对话框的工具类:

public class MydialogUtils {

    public static final MydialogUtils UTILS = new MydialogUtils();
    private View dialogView;
    private AlertDialog mDialog;


    public static MydialogUtils getInstance() {
        return UTILS;
    }

    public void showMyDialog(final Context context, final List<Bean> data) {
        Log.e("aaa", "aaa-->openMydialog");
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        if (dialogView == null) {
            dialogView = View.inflate(context, R.layout.dialog_layout, null);
        }
        builder.setView(dialogView);
        final TextView tvTitle = (TextView) dialogView
                .findViewById(R.id.tvTitle);
        final TextView tv0 = (TextView) dialogView.findViewById(R.id.tv0);
        final TextView tv1 = (TextView) dialogView.findViewById(R.id.tv1);
        final TextView tv2 = (TextView) dialogView.findViewById(R.id.tv2);
        final TextView tv3 = (TextView) dialogView.findViewById(R.id.tv3);
        final CheckBox cb0 = (CheckBox) dialogView.findViewById(R.id.cb0);
        final CheckBox cb1 = (CheckBox) dialogView.findViewById(R.id.cb1);
        final CheckBox cb2 = (CheckBox) dialogView.findViewById(R.id.cb2);
        final CheckBox cb3 = (CheckBox) dialogView.findViewById(R.id.cb3);
        final View layout0 = dialogView.findViewById(R.id.tv0Layout);
        final View layout1 = dialogView.findViewById(R.id.tv1Layout);
        final View layout2 = dialogView.findViewById(R.id.tv2Layout);
        final View layout3 = dialogView.findViewById(R.id.tv3Layout);
        tv0.setText(data.get(0).getStr());
        tv1.setText(data.get(1).getStr());
        tv2.setText(data.get(2).getStr());
        tv3.setText(data.get(3).getStr());
        cb0.setChecked(data.get(0).isCheck());
        cb1.setChecked(data.get(1).isCheck());
        cb2.setChecked(data.get(2).isCheck());
        cb3.setChecked(data.get(3).isCheck());
        layout0.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Bean bean = data.get(0);
                bean.setCheck(!bean.isCheck());
                cb0.setChecked(bean.isCheck());
            }
        });
        layout1.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Bean bean = data.get(1);
                bean.setCheck(!bean.isCheck());
                cb1.setChecked(bean.isCheck());
            }
        });
        layout2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Bean bean = data.get(2);
                bean.setCheck(!bean.isCheck());
                cb2.setChecked(bean.isCheck());
            }
        });
        layout3.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Bean bean = data.get(3);
                bean.setCheck(!bean.isCheck());
                cb3.setChecked(bean.isCheck());
            }
        });
        final TextView tvCancel = (TextView) dialogView
                .findViewById(R.id.tvCancel);
        final TextView tvOK = (TextView) dialogView.findViewById(R.id.tvOK);
        tvCancel.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                initData(data);
                closeMyDialog();
            }
        });
        tvOK.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.v("aaa", "#####start");
                for (Bean bean : data) {
                    Log.e("aaa", "" + bean);
                }
                Log.v("aaa", "#####start");
                // Log.e("aaa", "all-->" + data);
                closeMyDialog();

            }
        });

        if (mDialog == null)
            mDialog = builder.create();// 不能create多次!!!
        mDialog.show();

    }

    public void closeMyDialog() {
        if (mDialog != null && mDialog.isShowing())
            mDialog.dismiss();
    }

    private void initData(List<Bean> data) {
        if (data != null) {
            data.clear();
            data.add(new Bean("local system db", false));
            data.add(new Bean("local system file", true));
            data.add(new Bean("local private db", false));
            data.add(new Bean("local private file", true));
        }
    }
    public void destoryMydialog() {
        if (mDialog != null && mDialog.isShowing()) {
            mDialog.dismiss();
        }
        mDialog = null;
    }
}

   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125

工具类有点麻烦,不用去看,就是不要做成单例就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值