Unable to add window -- token android.os.BinderProxy...

1,673 阅读2分钟

前言

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

大家的解决方案

思路一

CSDN:mawei7510

1.一般展示dialog是异步的,或者另开一个线程。当activity关闭时调用dialog.show(),此时Activity已经不存在,必然报错。

所以,在dialog.show()之前加一个判断,判断Activity是否存在。

if (!XXActivity.this.isFinishing()) {
	dialog.show()
}

但是,我不管Activity是否finish,我就是要显示这个dialog。

思路二

CSDN:zdw890412

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的。