Caused by: android.view.WindowManager$BadTokenException:Unable to add window——token android.os.BinderProxy@196e65b8 is not valid;is your activit is running?
- 分析日志,根据日志可知原因:无法加载一个window,一个Binder 代理无效(BinderProxy),至于什么是Binder代理(BinderProxy)这里就不解释了。
那这个日志到底是什么意思呢那这个日志到底是什么意思呢?
其实也就是说,当你要显示一个View1,而此时View1所依赖的View不存在,或者finish了就会出现这样的问题,但是所依赖的View不存在的情况有很多种,这个原因,自己多debug 看看,具体为什么所依赖的View 不存在了。下面我复现一下我出现的这个问题情形。
1.1、主Activity
1.1.1、SinglerTonActivity .java
public class SinglerTonActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_singler_ton);
}
public void into(View v){ //此方法定义在下面的xml中
Intent intent = new Intent(SinglerTonActivity.this, A_Activity.class);
startActivity(intent);
}
}
1.1.2、activity_singler_ton.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="弹出淡漠Dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="into"
android:clickable="true"/>
</LinearLayout>
1.2、从SinglerTonActivity跳转到A_Activity
1.2.1、A_Activity.java
public class A_Activity extends AppCompatActivity {
private SingerTonDialog dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a_);
dialog = SingerTonDialog.getInstance(A_Activity.this);
}
public void showDialog(View v){
dialog.show();
}
}
1.2.2、activity_a_.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="弹出单例模式Dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="showDialog"
android:clickable="true"/>
</LinearLayout>
1.3、 弹出的Dialog
1.3.1、SingerTonDialog.java
public class SingerTonDialog {
private Dialog dialog;
public volatile static SingerTonDialog progress;
public static SingerTonDialog getInstance(Context context){
if (progress == null)
synchronized (AlertDialog.class){
if (progress == null)
progress = new SingerTonDialog(context);
}
return progress;
}
public SingerTonDialog(Context context){
View v = LayoutInflater.from(context).inflate(R.layout.singler_ton_dialog,null);
dialog = new Dialog(context,R.style.refresh_dialog);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT);
dialog.setContentView(v, params);
}
public SingerTonDialog show(){
dialog.show();
return progress;
}
public void dismiss(){
dialog.dismiss();
}
}
1.3.2、singler_ton_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="这是A_Activity中的对话框"
android:gravity="center"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="而且它还是单例模式哦"/>
</LinearLayout>
到此,代码片段贴完了。下面我们简单的分析分析这个依赖的View(此处为Activity)为什么空了
-
1、我们首先从SinglerTonActivity(主Activity)跳转到 A_Activity,
-
2、在 A_Activity中通过点击事件,弹出一个dialog
- 根据Activity的生命周期,每次跳转到 A_Activity,都会执行onCreate方法,那么就会去创建SingerTonDialog实例(对象),然后传入Context。
- 然后通过 SingerTonDialog 对象的 show方法弹出这个dialog。
-
问题:按照这个思路走,SingerTonDialog 所依赖的View (A_Activity)不是每次走了onCreate 等方法吗,既然走完了Activity的生命周期,按理说Activity应该存在啊,那么为什么此处出现了这个问题?我的Activity不存在?不应该,肯定的存在的。没错,我是这样的想的,奇怪,去趟WC。
-
回来突然想起来了,手残也SingerTonDialog的时候,把它写成了单例模式,而这个单例写的对于java来说,问题不大,但在此处问题却是致命。
-
看看SingerTonDialog这个类,我们用static volatile 关键字去修饰了这个对象,并且还是双重验证。
-
那么你看出来了吗?问题就出现在这个 static volatile 这,或者说 static 这,由于我用了static 修饰了这个类,那么SingerTonDialog 将会一直存在(至于什么时候GC回收,会不会回收等问题在此不解释)。
-
那么第一次创建SingerTonDialog这个对象的时候传进来的Context(Binger代理-BinderProxy@196e65b8)去创建Dialog,且创建后悔一直存在,在下一次在此创建的时候,由于这个对象一直存在,所以下一次就不会用新传进来的Context去创建Dlialog。
-
而是用上一次的Context去创建,但是上一次的Activity 不存在了,所以第二次开始,当点击事件弹出这个Dialog的时候就会出现这个问题。到此,原因应该解释清楚了,那么此情景解决办法应该也知道了吧,就不在此说了。
如有说错,欢迎大佬留言指正,权当记录错误,在此相互学习学习