前言
BadTokenException:Unable to add window -- token android.os.BinderProxy@3937915 is not valid; is your activity running?
网上有许多解决方案,不过和自己遇到的还有一些不同,故此记录一下。
细节
根据报错提示可以知道,activity在addView时发生错误,或者dialog在show时发生错误,错误的原因是dialog所依赖的context上下文 is destroy。
操作流程
登录->首页出现dialog->退出登录->登录->首页dialog报错。
通过try...catch捕获到错误信息为:You cannot start a load for a destroyed activity
大家的解决方案
思路一
1.一般展示dialog是异步的,或者另开一个线程。当activity关闭时调用dialog.show(),此时Activity已经不存在,必然报错。
所以,在dialog.show()之前加一个判断,判断Activity是否存在。
if (!XXActivity.this.isFinishing()) {
dialog.show()
}
但是,我不管Activity是否finish,我就是要显示这个dialog。
思路二
2.于是决定从context下手。那,context不跟随activity,既然都是上下文,我不用activity的context,用application的context如何?
可是,application的context并不代表任意的一个activity或者view,无法addview。
或者,每次使用这个工具类(备注:因为这里的dialog是由工具类utils持有,单例)的时候,重新赋值context一下。
(ps:也正是因为是单例、静态,使其持有的dialog在activity销毁后仍然存在,而在再次进入activity后,dialog的context和activity的context并不相同,但是当时我并不明白)
于是
while(activity.getParent()!=null) {
activity = activity.getParent();
}
new Dialog(activity,XXX);
这个方法对一般的dialog适用,但是对持有已销毁context的dialog是没效果的。
同样的,将dialog.show()放在主线程中一般的dialog是凑效的(Android – Displaying Dialogs From Background Threads),但,dialog是持有已销毁的context,仍会报
Unable to add window — token android.os.BinderProxy@447a6748 is not valid; is your activity running?
思路三
仔细看了一下代码,重复进行debug,最后才发现dialog持有的context和单例工具类中的context是不一样的,爆炸。这都是谁写的代码...... 放我个人的代码习惯,我是不会将dialog放在单例中,context生命周期需要注意。 找到问题答案,就重新new dialog(),处理问题。还有,需要注意的一点是,dialog的重复show()和dismiss()也是有可能造成exception的。