AndroidX Fragment探究-状态保存和恢复

概述

我们知道Activity提供了onSaveInstanceStateonRestoreInstanceState回调方法用于状态保存和恢复,同样FragmentActivity和Fragment也支持状态保存和恢复,FragmentActivity会在适当的时机,通过FragmentManagerImpl通知Fragment进行保存操作,接下来从源码中跟踪这个通知过程。

源码探究

文中源码基于’androidx.fragment:fragment:1.1.0’

状态保存

FragmentActivity重写了onSaveInstanceState方法:
[FragmentActivity.java]

protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    // ···
    // 调用FragmentController的saveAllState方法获取Parcelable
    Parcelable p = mFragments.saveAllState();
    if (p != null) {
        // 将Parcelable保存进outState,FRAGMENTS_TAG值为"android:support:fragments"
        outState.putParcelable(FRAGMENTS_TAG, p);
    }
    // ···
}

outState中以FRAGMENTS_TAG为key存储数据。

FragmentController的saveAllState方法中又调用FragmentManagerImpl的saveAllState方法:
[FragmentManagerImpl.java]

Parcelable saveAllState() {
    // Make sure all pending operations have now been executed to get
    // our state update-to-date.
    forcePostponedTransactions();
    endAnimatingAwayFragments();
    execPendingActions();

    // 标记状态保存为true
    mStateSaved = true;

    if (mActive.isEmpty()) {
        return null;
    }

    // First collect all active fragments.
    int size = mActive.size();
    ArrayList<FragmentState> active = new ArrayList<>(size);
    boolean haveFragments = false;
    for (Fragment f : mActive.values()) {
        if (f != null) {
            if (f.mFragmentManager != this) {
                throwException(new IllegalStateException(
                        "Failure saving state: active " + f
                                + " was removed from the FragmentManager"));
            }

            haveFragments = true;

            // 创建FragmentState用于保存Fragment中的成员变量值
            FragmentState fs = new FragmentState(f);
            active.add(fs);

            // fs.mSavedFragmentState此时默认为空
            if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
                // 派发通知fragment进行数据保存
                fs.mSavedFragmentState = saveFragmentBasicState(f);

                // 若有setTargetFragment,则进行TargetFragment相关数据保存
                if (f.mTargetWho != null) {
                    Fragment target = mActive.get(f.mTargetWho);
                    if (target == null) {
                        throwException(new IllegalStateException(
                                "Failure saving state: " + f
                                        + " has target not in fragment manager: "
                                        + f.mTargetWho));
                    }
                    if (fs.mSavedFragmentState == null) {
                        fs.mSavedFragmentState = new Bundle();
                    }
                    putFragment(fs.mSavedFragmentState,
                            FragmentManagerImpl.TARGET_STATE_TAG, target);
                    if (f.mTargetRequestCode != 0) {
                        fs.mSavedFragmentState.putInt(
                                FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
                                f.mTargetRequestCode);
                    }
                }

            } else {
                fs.mSavedFragmentState = f.mSavedFragmentState;
            }

            if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
                    + fs.mSavedFragmentState);
        }
    }

    if (!haveFragments) {
        if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
        return null;
    }

    ArrayList<String> added = null;
    BackStackState[] backStack = null;

    // Build list of currently added fragments.
    // 保存mAdded集合中的Fragment唯一ID
    size = mAdded.size();
    if (size > 0) {
        added = new ArrayList<>(size);
        for (Fragment f : mAdded) {
            // f.mWho为Fragment实例化时生成的唯一UUID
            added.add(f.mWho);
            if (f.mFragmentManager != this) {
                throwException(new IllegalStateException(
                        "Failure saving state: active " + f
                                + " was removed from the FragmentManager"));
            }
            if (DEBUG) {
                Log.v(TAG, "saveAllState: adding fragment (" + f.mWho
                        + "): " + f);
            }
        }
    }

    // Now save back stack.
    // 若有addToBackStack,则进行回退栈相关数据保存
    if (mBackStack != null) {
        size = mBackStack.size();
        if (size > 0) {
            backStack = new BackStackState[size];
            for (int i = 0; i < size; i++) {
                // 创建BackStackState用于保存BackStackRecord的数据
                backStack[i] = new BackStackState(mBackStack.get(i));
                if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
                        + ": " + mBackStack.get(i));
            }
        }
    }

    // 创建FragmentManagerState用于保存该FragmentManagerImpl整体数据
    FragmentManagerState fms = new FragmentManagerState();
    fms.mActive = active;
    fms.mAdded = added;
    fms.mBackStack = backStack;
    if (mPrimaryNav != null) {
        fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
    }
    fms.mNextFragmentIndex = mNextFragmentIndex;
    return fms;
}

该方法中创建FragmentState集合用以保存每个Fragment的数据,String集合保存每个Fragment的唯一ID,BackStackState数组保存每个BackStackRecord的数据,最终创建FragmentManagerState用以保存以上所有数据,并返回添加进Bundle中。

接着看saveFragmentBasicState方法,该方法中进行更详细的数据保存,返回Bundle赋值给FragmentState的mSavedFragmentState成员保存:
[FragmentManagerImpl.java]

Bundle saveFragmentBasicState(Fragment f) {
    Bundle result = null;

    if (mStateBundle == null) {
        mStateBundle = new Bundle();
    }
    // 触发Fragment的onSaveInstanceState回调方法;通知Fragment的子Fragment进行状态保存
    f.performSaveInstanceState(mStateBundle);
    // Lifecycle架构组件回调通知
    dispatchOnFragmentSaveInstanceState(f, mStateBundle, false);
    if (!mStateBundle.isEmpty()) {
        result = mStateBundle;
        mStateBundle = null;
    }

    // 若该fragment设置了view,则进行相关视图树的保存
    if (f.mView != null) {
        saveFragmentViewState(f);
    }
    if (f.mSavedViewState != null) {
        if (result == null) {
            result = new Bundle();
        }
        // 添加视图树数据
        result.putSparseParcelableArray(
                FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
    }
    if (!f.mUserVisibleHint) {
        if (result == null) {
            result = new Bundle();
        }
        // Only add this if it's not the default value
        // 不可见时保存mUserVisibleHint
        result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
    }

    return result;
}

该方法中会通过performSaveInstanceState方法触发Fragment的onSaveInstanceState回调方法,Fragment子类可重写该方法保存数据。若该Fragment有设置view,还将通过Fragment的mInnerView成员的saveHierarchyState方法进行视图树的保存。

在进行了这一系列的保存后,数据都整合添加进Bundle,由ActivityClientRecord的state成员保存,同时FragmentManagerImpl的mStateSaved被标记为true。

状态恢复

进入FragmentActivity的onCreate方法:
[FragmentActivity.java]

protected void onCreate(@Nullable Bundle savedInstanceState) {
    mFragments.attachHost(null /*parent*/);

    if (savedInstanceState != null) {
        // 当savedInstanceState不为空时,取出FRAGMENTS_TAG对应的数据
        Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
        // 将数据交给FragmentManagerImpl进行状态恢复
        mFragments.restoreSaveState(p);

        // Check if there are any pending onActivityResult calls to descendent Fragments.
        if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
            mNextCandidateRequestIndex =
                    savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
            int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
            String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
            if (requestCodes == null || fragmentWhos == null ||
                        requestCodes.length != fragmentWhos.length) {
                Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
            } else {
                mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
                for (int i = 0; i < requestCodes.length; i++) {
                    mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
                }
            }
        }
    }

    if (mPendingFragmentActivityResults == null) {
        mPendingFragmentActivityResults = new SparseArrayCompat<>();
        mNextCandidateRequestIndex = 0;
    }

    super.onCreate(savedInstanceState);

    mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    mFragments.dispatchCreate();
}

在onCreate中,若savedInstanceState不为空,则取出FRAGMENTS_TAG对应的数据,通过FragmentManagerImpl的restoreSaveState方法进行状态恢复。

接着看restoreSaveState方法:
[FragmentManagerImpl.java]

void restoreSaveState(Parcelable state) {
    // If there is no saved state at all, then there's nothing else to do
    if (state == null) return;
    FragmentManagerState fms = (FragmentManagerState)state;
    if (fms.mActive == null) return;

    // First re-attach any non-config instances we are retaining back
    // to their saved state, so we don't try to instantiate them again.
    // 处理setRetainInstance相关的Fragment的状态恢复
    for (Fragment f : mNonConfig.getRetainedFragments()) {
        if (DEBUG) Log.v(TAG, "restoreSaveState: re-attaching retained " + f);
        FragmentState fs = null;
        for (FragmentState fragmentState : fms.mActive) {
            if (fragmentState.mWho.equals(f.mWho)) {
                fs = fragmentState;
                break;
            }
        }
        if (fs == null) {
            // 若RetainedFragment对应的RetainedFragment不存在,则需要移除该RetainedFragment
            if (DEBUG) {
                Log.v(TAG, "Discarding retained Fragment " + f
                        + " that was not found in the set of active Fragments " + fms.mActive);
            }
            // We need to ensure that onDestroy and any other clean up is done
            // so move the Fragment up to CREATED, then mark it as being removed, then
            // destroy it.
            moveToState(f, Fragment.CREATED, 0, 0, false);
            f.mRemoving = true;
            moveToState(f, Fragment.INITIALIZING, 0, 0, false);
            continue;
        }
        fs.mInstance = f;
        f.mSavedViewState = null;
        f.mBackStackNesting = 0;
        f.mInLayout = false;
        f.mAdded = false;
        f.mTargetWho = f.mTarget != null ? f.mTarget.mWho : null;
        f.mTarget = null;
        if (fs.mSavedFragmentState != null) {
            // 恢复RetainedFragment的数据
        fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
            f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
                    FragmentManagerImpl.VIEW_STATE_TAG);
            f.mSavedFragmentState = fs.mSavedFragmentState;
        }
    }

    // Build the full list of active fragments, instantiating them from
    // their saved state.
    mActive.clear();
    for (FragmentState fs : fms.mActive) {
        if (fs != null) {
            // 实例化Fragment,并用FragmentState保存的数据来初始化Fragment
            Fragment f = fs.instantiate(mHost.getContext().getClassLoader(),
                    getFragmentFactory());
            f.mFragmentManager = this;
            if (DEBUG) Log.v(TAG, "restoreSaveState: active (" + f.mWho + "): " + f);
            // 添加fragment至mActive成员中
            mActive.put(f.mWho, f);
            // Now that the fragment is instantiated (or came from being
            // retained above), clear mInstance in case we end up re-restoring
            // from this FragmentState again.
            fs.mInstance = null;
        }
    }

    // Build the list of currently added fragments.
    mAdded.clear();
    if (fms.mAdded != null) {
        for (String who : fms.mAdded) {
            // 获取前面刚刚创建并保存的fragment
            Fragment f = mActive.get(who);
            if (f == null) {
                throwException(new IllegalStateException(
                        "No instantiated fragment for (" + who + ")"));
            }
            f.mAdded = true;
            if (DEBUG) Log.v(TAG, "restoreSaveState: added (" + who + "): " + f);
            if (mAdded.contains(f)) {
                throw new IllegalStateException("Already added " + f);
            }
            synchronized (mAdded) {
                // 添加进mAdded成员中
                mAdded.add(f);
            }
        }
    }

    // Build the back stack.
    // 后退栈数据恢复
    if (fms.mBackStack != null) {
        mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
        for (int i=0; i<fms.mBackStack.length; i++) {
            BackStackRecord bse = fms.mBackStack[i].instantiate(this);
            if (DEBUG) {
                Log.v(TAG, "restoreAllState: back stack #" + i
                        + " (index " + bse.mIndex + "): " + bse);
                LogWriter logw = new LogWriter(TAG);
                PrintWriter pw = new PrintWriter(logw);
                bse.dump("  ", pw, false);
                pw.close();
            }
            mBackStack.add(bse);
            if (bse.mIndex >= 0) {
                setBackStackIndex(bse.mIndex, bse);
            }
        }
    } else {
        mBackStack = null;
    }

    if (fms.mPrimaryNavActiveWho != null) {
        mPrimaryNav = mActive.get(fms.mPrimaryNavActiveWho);
        dispatchParentPrimaryNavigationFragmentChanged(mPrimaryNav);
    }
    this.mNextFragmentIndex = fms.mNextFragmentIndex;
}

该方法中利用保存在FragmentManagerState中的数据进行状态恢复,其中在利用FragmentState恢复Fragment数据时,会将mSavedFragmentState赋值给Fragment的mSavedFragmentState成员。
mSavedFragmentState中保存了Fragment中的自定义存储数据和视图树状态

之后随着FragmentActivity调度Fragment显示,在Fragment的各生命周期阶段中,可以使用mSavedFragmentState保存的数据恢复。

进入FragmentManagerImpl的生命周期状态调度方法moveToState:
[FragmentManagerImpl.java]

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
                 boolean keepActive) {
    // ···
    if (f.mState <= newState) {
        // ···
        switch (f.mState) {
            case Fragment.INITIALIZING:
                if (newState > Fragment.INITIALIZING) {
                    if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
                    if (f.mSavedFragmentState != null) {
                        f.mSavedFragmentState.setClassLoader(mHost.getContext()
                                .getClassLoader());
                        // 获取保存的视图树状态
                        f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
                                FragmentManagerImpl.VIEW_STATE_TAG);
                        Fragment target = getFragment(f.mSavedFragmentState,
                                FragmentManagerImpl.TARGET_STATE_TAG);
                        f.mTargetWho = target != null ? target.mWho : null;
                        if (f.mTargetWho != null) {
                            f.mTargetRequestCode = f.mSavedFragmentState.getInt(
                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
                        }
                        if (f.mSavedUserVisibleHint != null) {
                            f.mUserVisibleHint = f.mSavedUserVisibleHint;
                            f.mSavedUserVisibleHint = null;
                        } else {
                            // 获取保存的可见状态
                            f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
                                    FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
                        }
                        if (!f.mUserVisibleHint) {
                            f.mDeferStart = true;
                            if (newState > Fragment.ACTIVITY_CREATED) {
                                newState = Fragment.ACTIVITY_CREATED;
                            }
                        }
                    }

                    // ···
                    
                    if (f.mParentFragment == null) {
                        mHost.onAttachFragment(f);
                    } else {
                        f.mParentFragment.onAttachFragment(f);
                    }
                    dispatchOnFragmentAttached(f, mHost.getContext(), false);

                    if (!f.mIsCreated) {
                        dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                        // 触发Fragment的onCreate回调方法,并传入bundle
                        f.performCreate(f.mSavedFragmentState);
                        dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                    } else {
                        // 派发Fragment的子Fragment的状态恢复
                        f.restoreChildFragmentState(f.mSavedFragmentState);
                        f.mState = Fragment.CREATED;
                    }
                }
                // fall through
            case Fragment.CREATED:
                // We want to unconditionally run this anytime we do a moveToState that
                // moves the Fragment above INITIALIZING, including cases such as when
                // we move from CREATED => CREATED as part of the case fall through above.
                if (newState > Fragment.INITIALIZING) {
                    ensureInflatedFragmentView(f);
                }

                if (newState > Fragment.CREATED) {
                    if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                    if (!f.mFromLayout) {
                        ViewGroup container = null;
                        if (f.mContainerId != 0) {
                            // ···
                        }
                        f.mContainer = container;
                        // 触发Fragment的onCreateView回调方法,并传入bundle
                        f.performCreateView(f.performGetLayoutInflater(
                                f.mSavedFragmentState), container, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mInnerView = f.mView;
                            f.mView.setSaveFromParentEnabled(false);
                            if (container != null) {
                                container.addView(f.mView);
                            }
                            if (f.mHidden) {
                                f.mView.setVisibility(View.GONE);
                            }
                            // 触发Fragment的onViewCreated回调方法,并传入bundle
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                            dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                    false);
                            // Only animate the view if it is visible. This is done after
                            // dispatchOnFragmentViewCreated in case visibility is changed
                            f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                                    && f.mContainer != null;
                        } else {
                            f.mInnerView = null;
                        }
                    }

                    // 触发Fragment的onActivityCreated回调方法,并传入bundle
                    f.performActivityCreated(f.mSavedFragmentState);
                    dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                    if (f.mView != null) {
                        // 调用mInnerView的restoreHierarchyState方法传入mSavedViewState进行视图树状态恢复。
                        // 然后回调onViewStateRestored方法并传入bundle。
                        f.restoreViewState(f.mSavedFragmentState);
                    }
                    // mSavedFragmentState赋值为空
                    f.mSavedFragmentState = null;
                }
                // fall through
            case Fragment.ACTIVITY_CREATED:
                if (newState > Fragment.ACTIVITY_CREATED) {
                    if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                    f.performStart();
                    dispatchOnFragmentStarted(f, false);
                }
                // fall through
            case Fragment.STARTED:
                if (newState > Fragment.STARTED) {
                    if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                    f.performResume();
                    dispatchOnFragmentResumed(f, false);
                    f.mSavedFragmentState = null;
                    f.mSavedViewState = null;
                }
        }
    } else if (f.mState > newState) { /* ··· */ }
    // ···
}

从该方法中可以看出,在Fragment的生命周期回调方法中收到的savedInstanceState入参即为Fragment的mSavedFragmentState,在派发完成后又会将mSavedFragmentState赋值为空。

commit & commitAllowingStateLoss

这里看下提交事务的两个方法:commit、commitAllowingStateLoss,顾名思义,它们一个在提交时不允许状态丢失、另一个允许。

[BackStackRecord.java]

public int commit() {
    return commitInternal(false);
}

public int commitAllowingStateLoss() {
    return commitInternal(true);
}

都调用了同一个方法commitInternal,只是传入参数不同,一个传false,另一个传true。

继续看commitInternal方法:
[BackStackRecord.java]

int commitInternal(boolean allowStateLoss) {
    // ···
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

allowStateLoss参数直接传入添加事务队列的方法。

[FragmentManagerImpl.java]

public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        // 不允许状态丢失时,首先进行检查
        checkStateLoss();
    }
    synchronized (this) {
        if (mDestroyed || mHost == null) {
            // 当FragmentActivity已经destroyed或持有FragmentHostCallback为空时,若不允许状态丢失,将抛出异常。
            if (allowStateLoss) {
                // This FragmentManager isn't attached, so drop the entire transaction.
                return;
            }
            throw new IllegalStateException("Activity has been destroyed");
        }
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<>();
        }
        mPendingActions.add(action);
        scheduleCommit();
    }
}

是否允许状态丢失,就是在添加事务进队列前,检查状态,以及是否抛出异常。

进入checkStateLoss方法:
[FragmentManagerImpl.java]

private void checkStateLoss() {
    // 检查状态,判断是否抛异常
    if (isStateSaved()) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
}

@Override
public boolean isStateSaved() {
    // See saveAllState() for the explanation of this.  We do this for
    // all platform versions, to keep our behavior more consistent between
    // them.
    // onSaveInstanceState时mStateSaved将置为true,onStop时mStopped将置为true
    return mStateSaved || mStopped;
}

不允许在执行onSaveInstanceState回调方法后再添加Fragment事务操作。因为Fragment的状态保存是在onSaveInstanceState阶段中,此后若再变更FragmentManagerImpl中的Fragment,这些Fragment的状态不会进行保存。

onSaveInstanceState回调在Android P及以上版本触发时机在onStop之后,在低版本触发时机在onStop之前。

总结

FragmentActivity在onSaveInstanceState回调方法中,调用FragmentManagerImpl通知其管理的Fragment进行状态保存。保存过程中会触发Fragment的onSaveInstanceState回调,可通过重写该方法保存自定义数据。若Fragment有设置view,还将进行视图树的保存。

FragmentActivity在onCreate回调方法中,判断savedInstanceState参数是否有值,之后通知FragmentManagerImpl进行状态恢复,实例化Fragment并将存储着状态的bundle赋值给mSavedFragmentState成员。

在Fragment从创建到显示的生命周期状态生长阶段,通过mSavedFragmentState成员来恢复数据和视图树,会将mSavedFragmentState作为入参调用对应生命周期回调方法,完成后再清除mSavedFragmentState。Fragment子类可在onCreate和onActivityCreated中恢复自定义数据。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章