java.lang.IllegalStateException: Fragment already added异常的处理

1.当快速双击调用FragmentTransaction.add()方法添加fragmentA,而fragmentA不是每次单独生成的因为DialogFragment.show()内部调用了FragmentTransaction.add()方法,所以调用DialogFragment.show()方法时候也可能会出现这个异常。

开始想在add()方法时候,先判断fragmentA.isAdded(),如下调用可以避免该异常:

if(!fragmentA.isAdded()){
                    FragmentManager manager = ((FragmentActivity)context).getSupportFragmentManager();
                    FragmentTransaction ft = manager.beginTransaction();
                    ft.add(fragmentA, "fragment_name");
                    ft.commit();
}

后来发现,在不断快速切换不同的Fragment的时候,isAdded()偶尔会显示false,就因为isAdded()显示了false,那么 ft.add( R.id.main_content, fragment )就会再次执行一次,就会报错,说明通过isAdded()这个方法判断Fragment是否被add可能并不准确。

最终解决方法:
解决方法就是每次add的时候加上一个tag,然后不仅要通过isAdded()判断Fragment是否add,还要通过FragmentManager.findFragmentByTag(tag)获取Fragment,然后判断此Fragment是否为null。

 private void addFragment(FragmentManager fm, Fragment fragment, String tag) {
        if (!fragment.isAdded()&&null == fm.findFragmentByTag( tag )) {
            FragmentTransaction ft = fm.beginTransaction();
            fm.executePendingTransactions();
            ft.add( R.id.main_content, fragment, tag );
            ft.commitAllowingStateLoss();
        }
    }

2.DialogFragment的show方法引发的该bug

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

public void show(FragmentManager manager, String tag) {
        mDismissed = false;
        mShownByMe = true;
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commit();
    }

所以当快速多次点击按钮时,调用了多次的show方法,添加了多个add事务(add事务A、add事务B等等)。
然后系统在执行事务队列时,在执行了add Fragment后,发现又要add这个fragment,就报异常了,FragmentManager中源码:

    public void addFragment(Fragment fragment, boolean moveToStateNow) {
        if (DEBUG) Log.v(TAG, "add: " + fragment);
        makeActive(fragment);
        if (!fragment.mDetached) {
            if (mAdded.contains(fragment)) {
                throw new IllegalStateException("Fragment already added: " + fragment);
            }
            synchronized (mAdded) {
                mAdded.add(fragment);
            }
            fragment.mAdded = true;
            fragment.mRemoving = false;
            if (fragment.mView == null) {
                fragment.mHiddenChanged = false;
            }
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            if (moveToStateNow) {
                moveToState(fragment);
            }
        }
    }

就是快速多次点击按钮时,添加了多个连续的add事务,
而系统在执行add fragment时如果已经add过了当前fragment,则不允许再add,add就报异常。

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

public class TestDialogFragment extends DialogFragment {

    其他代码......

    @Override
    public void show(FragmentManager manager, String tag) {
        try {
            //在每个add事务前增加一个remove事务,防止连续的add
            manager.beginTransaction().remove(this).commit();
            super.show(manager, tag);
        } catch (Exception e) {
            //同一实例使用不同的tag会异常,这里捕获一下
            e.printStackTrace();
        }
    }
    原文作者:锐心凌志
    原文地址: https://www.jianshu.com/p/1068f9f75fe4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞