DialogFragment异常Fragment already added的原因与解决办法

DialogFragment异常的表现形式

快速多次点击按钮展示DialogFragment弹框,100%复现崩溃

1
java.lang.IllegalStateException: Fragment already added: XXDialogFragment

DialogFragment异常的发生原因

查看DialogFragment的show方法源码,发现每次show的时候都会提交一个add fragment的事务。

DialogFragment.java

1
2
3
4
5
6
7
public void show(FragmentManager manager, String tag) {
this.mDismissed = false;
this.mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}

当快速多次点击按钮时,短时间内调用多次show方法,添加多个add事务(add事务A、add事务B等)。然后系统在执行事务队列时,在执行了addFragment后,发现又要add这个Fragment,即抛出异常:

FragmentManagerImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (DEBUG) {
Log.v("FragmentManager", "add: " + fragment);
}

this.makeActive(fragment);
if (!fragment.mDetached) {
if (this.mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}

synchronized(this.mAdded) {
this.mAdded.add(fragment);
}

fragment.mAdded = true;
...
}

}

DialogFragment异常的解决办法

既然知道异常的原因是“执行了多次show方法,添加了多个连续的add事务”。那就改写下show方法,让add事务不连续,每次add之前都把原来的remove掉。解决代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ActivityDialogFragment extends DialogFragment {

@Override
public void show(FragmentManager manager, String tag) {
NLog.i("yezhou", "ActivityDialogFragment.show");
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
if (manager.isDestroyed())
return;
}
try {
//在每个add事务前增加一个remove事务,防止连续的add
manager.beginTransaction().remove(this).commit();
super.show(manager, tag);
} catch (Exception e) {
//同一实例使用不同的tag会异常,这里捕获一下
e.printStackTrace();
}
}
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :