android(18): Fragment常见的坑 - clarkehe/Android GitHub Wiki

Fragment Detach后操作异常

异常
java.lang.IllegalStateException: Fragment a{3b4d2620} not attached to Activity android.support.v4.app.Fragment.getResources(ProGuard:639)

原因分析:

Add Fragment异常

异常1
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState android.support.v4.app.FragmentManagerImpl.checkStateLoss(ProGuard:1489) android.support.v4.app.FragmentManagerImpl.enqueueAction(ProGuard:1507) android.support.v4.app.BackStackRecord.commitInternal(ProGuard:634) android.support.v4.app.BackStackRecord.commit(ProGuard:613) android.support.v4.app.DialogFragment.show(ProGuard:139)

异常2
java.lang.IllegalStateException: Activity has been destroyed android.support.v4.app.FragmentManagerImpl.enqueueAction(ProGuard:1511) android.support.v4.app.BackStackRecord.commitInternal(ProGuard:634) android.support.v4.app.BackStackRecord.commitAllowingStateLoss(ProGuard:617)

原因分析: 第一个异常是使用DialogFragment出现的异常。DialogFragment本质还是添加一个Fragment到Host Activity中。看下DialogFragment的show的实现:

    /**
     * Display the dialog, adding the fragment to the given FragmentManager.  This
     * is a convenience for explicitly creating a transaction, adding the
     * fragment to it with the given tag, and committing it.  This does
     * <em>not</em> add the transaction to the back stack.  When the fragment
     * is dismissed, a new transaction will be executed to remove it from
     * the activity.
     * @param manager The FragmentManager this fragment will be added to.
     * @param tag The tag for this fragment, as per
     * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
     */
    public void show(FragmentManager manager, String tag) {
        mDismissed = false;
        mShownByMe = true;
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commit();
    }

异常1是说在Add Fragment时,Host Activity是已经调用了onSaveInstanceState,此时Host Activity一般是退到了后台。onSaveInstanceState是保存Activity的状态,在Activity被回收后,方便进行恢复。onSaveInstanceState之后Add Fragment,Fragment没有机会再保存状态,回收了没有数据进行恢复。

解决方法有好几种,最简单的是自己实现show的方法,在Add Fragment时,使用commitAllowingStateLoss,允许Fragment状态丢失。

        FragmentManager fm = fragmentActivity.getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.add(this, this.getClass().getSimpleName());
        ft.commitAllowingStateLoss();

还有一种方法时,将Add Fragment的时机延迟到Activity的onResume方法。

异常2也是Host Activity的生命周期问题。在Add Fragment时,Host Activity是已经Destroy了。此时Add Fragment已经没有意义了。处理起来很简单,在Add Fragment前判断下Host Activity的状态,如果Destroy了,就直接返回。

        if (fragmentActivity == null || fragmentActivity.isFinishing() || isAdded()) {
            return;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            if(fragmentActivity.isDestroyed()) {
                return;
            }
        }
⚠️ **GitHub.com Fallback** ⚠️