Android :我的奇怪BUG:WindowManager$BadTokenException

来源:互联网 发布:医学必备数据分析软件 编辑:程序博客网 时间:2024/06/02 13:51
  • 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)
  • 这个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();    }}
  • 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;    }}

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

0 0
原创粉丝点击