DialogFragment异常的表现形式
快速多次点击按钮展示DialogFragment弹框,100%复现崩溃
java.lang.IllegalStateException: Fragment already added: XXDialogFragment
DialogFragment异常的发生原因
查看DialogFragment的show方法源码,发现每次show的时候都会提交一个add fragment的事务。
DialogFragment.java
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
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掉。解决代码如下:
public class ActivityDialogFragment extends DialogFragment { @Override public void show(FragmentManager manager, String tag) { 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(); } } }