Fragment源碼解析三——狀態(tài)保存與恢復(fù)

這一篇單獨(dú)來說一說Fragment的狀態(tài)保存和恢復(fù)。

狀態(tài)保存

只要Activity不是被主動finish的,狀態(tài)的保存與恢復(fù)機(jī)制就會被觸發(fā),包括 :Activity因?yàn)閮?nèi)存不足被killed、其他命令殺死進(jìn)程、手機(jī)配置改變導(dǎo)致的Activity重建(用戶沒有手動處理配置改變的情況下)。導(dǎo)致onSaveInstanceState(在onStop之前)和onRestoreInstanceState(在onStart之后)的回調(diào)。而配置的改變還會在onDestroy之前引發(fā)Activity的另一個回調(diào)onRetainNonConfigurationInstance()。這兩個回調(diào)相互獨(dú)立,所保存的內(nèi)容也不相同。

onSaveInstanceState

onSaveInstanceState方法的參數(shù)outState是一個Bundle對象,是系統(tǒng)保存狀態(tài)時持久化狀態(tài)的容器,在該方法中會調(diào)用 Parcelable p = mFragments.saveAllState() ,Fragment的狀態(tài)以Parcelable的形式保存在outState中。

//FragmentActivity.java
protected void onSaveInstanceState(Bundle outState) {
    ...
    Parcelable p = mFragments.saveAllState();
    if (p != null) {
        outState.putParcelable(FRAGMENTS_TAG, p);
    }
    ...
}

保存的內(nèi)容

既然調(diào)用了mFragments的saveAllState(),我們看一下這個方法總體上做了什么事情。mFragments是一個FragmentController對象,它持有Activity的很多信息,負(fù)責(zé)管理Fragment,它對Fragment的控制最終也是由FragmentManagerImpl這個類實(shí)現(xiàn)的。方法大部分省略了,最后我們可以看到,新建了一個FragmentManagerState,并對其3個成員賦值,F(xiàn)ragmentManagerState對象保存了FragmentManagerImpl對象中的基本信息,作為一個可序列化的對象交給系統(tǒng)。

//FragmentManagerImpl.java
Parcelable saveAllState() {
        .....
        FragmentManagerState fms = new FragmentManagerState();
        fms.mActive = active;
        fms.mAdded = added;
        fms.mBackStack = backStack;
        return fms;
    }
//FragmentManagerState.java
final class FragmentManagerState implements Parcelable {
    FragmentState[] mActive;
    int[] mAdded;
    BackStackState[] mBackStack;
    ...
}

mActive成員

看一下fms.mActive,它是一個FragmentState[](對應(yīng)著FragmentManagerImpl#mActive),F(xiàn)ragmentState和Fragment在同一個包中,實(shí)現(xiàn)了Parcelable接口,對應(yīng)著一個Fragment實(shí)例,保存了Fragment的一些狀態(tài),我們看一下它的成員就知道,分為兩類,一類是tag、arguments、mRetainInstance這樣的變量,還有一類是Bundle mSavedFragmentState,它用來保存一些其他的狀態(tài)。這兩類信息足以代表一個Fragment的狀態(tài),F(xiàn)ragmentState把它們都封裝了起來。

    //FragmentState.java
    final String mClassName;
    final int mIndex;
    final boolean mFromLayout;
    final int mFragmentId;
    final int mContainerId;
    final String mTag;
    final boolean mRetainInstance;
    final boolean mDetached;
    final Bundle mArguments;
    
    Bundle mSavedFragmentState;
    
    Fragment mInstance;

我們看下FragmentManagerImpl具體是怎樣將Fragment的狀態(tài)保存在FragmentState中的,還是在saveAllState() 方法中

  • FragmentState fs = new FragmentState(f);
    前面說的第一類基本變量

  • fs.mSavedFragmentState = saveFragmentBasicState(f);
    前面說的第二類其他狀態(tài)

    • 調(diào)用Fragment的onSaveInstanceState(保存用戶自己需要保存的變量),同時將saveAllState()分發(fā)給子FragmentManager,完成了狀態(tài)保存的分發(fā)。
    • 保存Fragment的View樹狀態(tài)
    • 保存了用戶可見性狀態(tài)mUserVisibleHint
  • 如果f.mTarget不空,保存相關(guān)狀態(tài)

    //FragmentManagerImpl.java
    Parcelable saveAllState() {
        ...
        if (mActive == null || mActive.size() <= 0) {
            return null;
        }
        int N = mActive.size();
        FragmentState[] active = new FragmentState[N];
        ...
        for (int i=0; i<N; i++) {
            //遍歷FragmentManagerImpl的mActive成員
            Fragment f = mActive.get(i);
            if (f != null) {
                if (f.mIndex < 0) {
                    throwException(new IllegalStateException(...);
                }
                ...
                //保存第一類變量
                FragmentState fs = new FragmentState(f);
                active[i] = fs;
                // 對處于正常生命周期狀態(tài)下的Fragment。
                if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
                    //保存第二類變量,以Bundle的形式,包括子Fragment狀態(tài),視圖狀態(tài),mUserVisibleHint
                    fs.mSavedFragmentState = saveFragmentBasicState(f);
                    // 同時,如果Fragment有target,還需要保存target對應(yīng)的索引index, 以及target的mTargetRequestCode
                    if (f.mTarget != null) {
                        if (f.mTarget.mIndex < 0) {
                            throwException(new IllegalStateException(...);
                        }
                        if (fs.mSavedFragmentState == null) {
                            fs.mSavedFragmentState = new Bundle();
                        }
                        
                        putFragment(fs.mSavedFragmentState, FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
                        
                        if (f.mTargetRequestCode != 0) {
                            fs.mSavedFragmentState.putInt(FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, f.mTargetRequestCode);
                        }
                    }
                } else {
                    fs.mSavedFragmentState = f.mSavedFragmentState;
                }
            }
        }
        ...
    }

mSavedFragmentState這個Bundle中保存了以下這些狀態(tài):

信息(Bundle’s Key) 備注
TARGET_STATE_TAG target的index
TARGET_REQUEST_CODE_STATE_TAG target的requestCode
VIEW_STATE_TAG 視圖層級狀態(tài)
USER_VISIBLE_HINT_TAG mUserVisibleHint字段
FragmentActivity.FRAGMENTS_TAG 子FragmentManager下所維護(hù)的所有Fragment的狀態(tài)
onSaveInstanceState(outState) 供用戶手動保存的狀態(tài)

mAdded成員

mAdded是一個int[]型數(shù)組,被用來保存當(dāng)前已經(jīng)被added到FragmentManager下的所有fragments的index 。

// FragmentManagerImpl.java
Parcelable saveAllState() {
  ...
  if (mAdded != null) {
      N = mAdded.size();
      if (N > 0) {
          added = new int[N];
          for (int i=0; i<N; i++) {
              // 依次遍歷mAdded數(shù)組,將Fragment對應(yīng)的index添加至added
              added[i] = mAdded.get(i).mIndex;
              if (added[i] < 0) {
                  throwException(new IllegalStateException(...);
              }
          }
      }
  }
  ...
}

mBackStack成員

BackStackState保存已經(jīng)被添加到回退棧的BackStackRecord中的內(nèi)容。

//BackStackState.java
    final int[] mOps;
    final int mTransition;
    final int mTransitionStyle;
    final String mName;
    final int mIndex;
    final int mBreadCrumbTitleRes;
    final CharSequence mBreadCrumbTitleText;
    final int mBreadCrumbShortTitleRes;
    final CharSequence mBreadCrumbShortTitleText;
    final ArrayList<String> mSharedElementSourceNames;
    final ArrayList<String> mSharedElementTargetNames;

保存了FragmentManagerImpl的mBackStack成員。

// FragmentManagerImpl.java
Parcelable saveAllState() {
  ...
    if (mBackStack != null) {
            N = mBackStack.size();
            if (N > 0) {
                backStack = new BackStackState[N];
              //遍歷FragmentManagerImpl的mBackStack并保存
                for (int i=0; i<N; i++) {
                    backStack[i] = new BackStackState(mBackStack.get(i));
                    if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
                            + ": " + mBackStack.get(i));
                }
            }
        }
  ...
}       

小結(jié)

可以看到,F(xiàn)ragment的狀態(tài)保存的觸發(fā)在Activity的onSaveInstanceState 中,分別對FragmentManagerImpl中的mActive、mAdded、mBackStack成員進(jìn)行了相應(yīng)的保存。其中對mActive的保存,也就是對應(yīng)Fragment的保存,涉及到基本變量、用戶自定義保存變量、子FragmentManagerImpl需要保存的變量、視圖狀態(tài)變量、fragment的target等相關(guān)變量;對mAdded的保存,是把對應(yīng)Fragment的index保存;對mBackStack的保存,是對對應(yīng)BackStackRecord的相關(guān)變量的保存。最后以FragmentManagerState實(shí)例的形式返回。

NoConfig下的狀態(tài)保存

在Manifest中未對Activity進(jìn)行android:configChanges配置,稱為NonConfig 。這時候如果設(shè)備配置發(fā)生改變,Activity會被銷毀并重建。在這種情況下,Activity的onSaveInstanceState 依舊會被調(diào)用。但是對于Fragment,我們可能希望其中的一些工作不被中斷,因此Fragment可調(diào)用setRetainInstance(true),在設(shè)備配置改變時,系統(tǒng)在銷毀Activity前(onDestroy中)會回調(diào)Activity#onRetainNonConfigurationInstance() ,F(xiàn)ragment實(shí)例不會被銷毀,而是被保存在了特殊的對象里交給了ActivityThread對象,也就是說Fragment的對象直接緩存在了內(nèi)存中,區(qū)別于上面的將Fragment的實(shí)例狀態(tài)持久化(雖然這個持久化動作依然會進(jìn)行)。如果我們在mainfest中配置了Activity的android:configChanges屬性,那么這個方法不會調(diào)用。

// FragmentActivity.java
@Override
public final Object onRetainNonConfigurationInstance() {
    ...
    FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
    ...
    NonConfigurationInstances nci = new NonConfigurationInstances();
    ...
    nci.fragments = fragments;
    ...
    return nci;
}

同樣,也是由FragmentManagerImpl這個類實(shí)現(xiàn)的,將需要 保持實(shí)例的Fragment集合 及 其相應(yīng)的嵌套子Fragment實(shí)例集合 都保存在了FragmentManagerNonConfig對象中并返回,F(xiàn)ragmentActivity將得到的該對象又被包裝在NonConfigurationInstances里返回給了系統(tǒng)。

    ArrayList<Fragment> retainNonConfig() {
        ArrayList<Fragment> fragments = null;
        if (mActive != null) {
            for (int i=0; i<mActive.size(); i++) {
                Fragment f = mActive.get(i);
                //如果實(shí)例具有mRetainInstance標(biāo)志位,這個標(biāo)志位在setRetainInstance中設(shè)置
                if (f != null && f.mRetainInstance) {
                    if (fragments == null) {
                        fragments = new ArrayList<Fragment>();
                    }
                    fragments.add(f);
                    //設(shè)置其mRetaining標(biāo)志位,這個標(biāo)志位將對Fragment的生命周期回調(diào)產(chǎn)生影響
                    f.mRetaining = true;
                    f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
                    if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
                }
            }
        }
        return fragments;
    }

兩種狀態(tài)保存的總結(jié)

保存分為兩種情況:一、內(nèi)存不足或進(jìn)程被其他軟件殺死。二、設(shè)備配置的改變。這兩種情況都會觸發(fā)FragmentActivity的onSaveInstanceState 回調(diào),而在設(shè)備配置改變的情況下還會回調(diào)FragmentActivity的onRetainNonConfigurationInstance() 。這兩個回調(diào)是獨(dú)立的,也就是說在配置改變的情況下,這兩個方法都會被回調(diào)。值得一提的是setRetainInstance(true) 若能產(chǎn)生效果只會是在配置發(fā)生改變的時候,若Activity只是被killed,那么這個函數(shù)起不到任何作用,實(shí)例依然會被銷毀(涉及到Fragment的mRetaining字段的改變),只能通過onSaveInstanceState回調(diào)保存一些變量, 如果 setRetainInstance(false) 的話Fragment依舊只能恢復(fù)一些變量。

狀態(tài)恢復(fù)

NonConfigurationInstances被重新賦值到Activity中

在Activity被create時,Activity里首次被調(diào)用的方法是attach(…):,在該方法中系統(tǒng)傳入了緩存在ActivityTread中的lastNonConfigurationInstances

final void attach(...NonConfigurationInstances lastNonConfigurationInstances...) {
    ...
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    ...
}

所有Fragment的狀態(tài)恢復(fù)

在接下來的生命周期回調(diào)onCreate中,Activity使用了可能存在的NonConfigurationInstances實(shí)例以及一定存在的所有Fragment的持久化數(shù)據(jù) 對其所管轄的所有Fragment進(jìn)行狀態(tài)恢復(fù)。狀態(tài)恢復(fù)過后,所有Fragment的狀態(tài)都是INITIALZING,接著調(diào)用dispatchCreate() 方法進(jìn)行生命周期的轉(zhuǎn)移。

// FragmentActivity.java
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ...
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            mFragments.restoreLoaderNonConfig(nc.loaders);
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);

            ....
        }
        ...
        mFragments.dispatchCreate();
    }

mFragments.restoreAllState是狀態(tài)恢復(fù)的入口,mFragments.restoreAllState最終將事件分發(fā)給了FragmentManagerImpl的restoreAllState方法,這個方法利用FragmentManagerState恢復(fù)了FragmentManagerImpl的狀態(tài)。

// FragmentManagerImpl.java
void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
    ...
    FragmentManagerState fms = (FragmentManagerState)state;
    ...
    // step1
    if (nonConfig != null) {
        ...
    }
    ...
    // step2
    for (int i=0; i<fms.mActive.length; i++) {
        FragmentState fs = fms.mActive[i];
        if (fs != null) {
            ...
        }
    }
    // step3
    if (nonConfig != null) {
        ...
    }
    ...
    // step4
    if (fms.mAdded != null) {
        ...
    }
    ...
    // step5
    if (fms.mBackStack != null) {
        ...
    }
    ...
}

(1)將內(nèi)存中的Fragment實(shí)例關(guān)聯(lián)至FragmentManagerState的FragmentState[]

我們知道持久化的FragmentManagerState中有一個mActive成員,它是一個FragmentState[],代表了所有的Fragment(被添加到回退棧和被添加到Activity中的),我們將緩存的Fragment實(shí)例賦值給對應(yīng)的FragmentState的mInstance成員,那么在接下來的步驟就不用根據(jù)持久化的基本變量重建一個新的Fragment了。

// FragmentManager # restoreAllState()
if (nonConfig != null) {
    List<Fragment> nonConfigFragments = nonConfig.getFragments();
    childNonConfigs = nonConfig.getChildNonConfigs();
    final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
    for (int i = 0; i < count; i++) {
        // 得到保持的實(shí)例對象
        Fragment f = nonConfigFragments.get(i);
        // 取出實(shí)例對象在保存了狀態(tài)的數(shù)組中對應(yīng)的FragmentState
        FragmentState fs = fms.mActive[f.mIndex];
        // 將實(shí)例關(guān)聯(lián)到對應(yīng)的FragmentState
        fs.mInstance = f;
        f.mSavedViewState = null;
        f.mBackStackNesting = 0;
        f.mInLayout = false;
        f.mAdded = false;
        f.mTarget = null;
        if (fs.mSavedFragmentState != null) {
            fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
            f.mSavedViewState =FragmentManagerImpl.VIEW_STATE_TAG);
            f.mSavedFragmentState = fs.mSavedFragmentState;
        }
    }
}

(2)恢復(fù)FragmentManagerImpl的mAvtive成員

由FragmentManagerState的mActive恢復(fù)對應(yīng)的FragmentManagerImpl的mAvtive。

// FragmentManager # restoreAllState()
for (int i=0; i<fms.mActive.length; i++) {
    FragmentState fs = fms.mActive[i];
    if (fs != null) {
        FragmentManagerNonConfig childNonConfig = null;
        if (childNonConfigs != null && i < childNonConfigs.size()) {
            // 拿到Fragment的子Fragment的實(shí)例
            childNonConfig = childNonConfigs.get(i);
        }
        // 該方法通過FragmentState保存的狀態(tài)返回一個Fragment實(shí)例
        Fragment f = fs.instantiate(mHost, mParent, childNonConfig);
        // 添加
        mActive.add(f);
       
        fs.mInstance = null;
    } else {
        mActive.add(null);
        if (mAvailIndices == null) {
            mAvailIndices = new ArrayList<Integer>();
        }
        if (DEBUG) Log.v(TAG, "restoreAllState: avail #" + i);
        mAvailIndices.add(i);
    }
}

其中FragmentState的instantiate() 方法如下,可以看到如果前面關(guān)聯(lián)了緩存的Fragment實(shí)例,就直接返回mInstance,否則利用反射的方式創(chuàng)建一個Fragment實(shí)例并賦值給mInstance,接著為它的成員賦值,包括mArguments等一些基本變量,mSavedFragmentState這樣保存了用戶自定義變量和View狀態(tài)的Bundle。

// FragmentState.java
public Fragment instantiate(FragmentHostCallback host, Fragment parent, FragmentManagerNonConfig childNonConfig) {
    if (mInstance == null) {
        final Context context = host.getContext();
        if (mArguments != null) {
            mArguments.setClassLoader(context.getClassLoader());
        }
        //反射
        mInstance = Fragment.instantiate(context, mClassName, mArguments);
        if (mSavedFragmentState != null) {
            mSavedFragmentState.setClassLoader(context.getClassLoader());
            mInstance.mSavedFragmentState = mSavedFragmentState;
        }
        mInstance.setIndex(mIndex, parent);
        mInstance.mFromLayout = mFromLayout;
        mInstance.mRestored = true;
        mInstance.mFragmentId = mFragmentId;
        mInstance.mContainerId = mContainerId;
        mInstance.mTag = mTag;
        mInstance.mRetainInstance = mRetainInstance;
        mInstance.mDetached = mDetached;
        mInstance.mHidden = mHidden;
        mInstance.mFragmentManager = host.mFragmentManager;
    }
    mInstance.mChildNonConfig = childNonConfig;
    return mInstance;
}

(3)更新保存的在內(nèi)存中的Fragment的mTarget成員

// FragmentManager # restoreAllState()
// Update the target of all retained fragments.
        if (nonConfig != null) {
            for (int i=0; i<nonConfig.size(); i++) {
                Fragment f = nonConfig.get(i);
                if (f.mTargetIndex >= 0) {
                    if (f.mTargetIndex < mActive.size()) {
                        f.mTarget = mActive.get(f.mTargetIndex);
                    } else {
                        Log.w(TAG, "Re-attaching retained fragment " + f
                                + " target no longer exists: " + f.mTargetIndex);
                        f.mTarget = null;
                    }
                }
            }
        }

(4)恢復(fù)FragmentManagerImpl的mAdded成員

由FragmentManagerState的mAdded恢復(fù)對應(yīng)的FragmentManagerImpl的mAdded。注意FragmentManagerState中持久化的是一個int[],這里根據(jù)其已經(jīng)恢復(fù)好的mActive來把FragmentManagerState中的int[]轉(zhuǎn)化成FragmentManagerImpl中的ArrayList < Fragment >

// FragmentManager # restoreAllState()
if (fms.mAdded != null) {
    // 該數(shù)組保存的是已經(jīng)Add的Fragment在mActive對應(yīng)是索引
    mAdded = new ArrayList<Fragment>(fms.mAdded.length);
    for (int i=0; i<fms.mAdded.length; i++) {
        Fragment f = mActive.get(fms.mAdded[i]);
        if (f == null) {
            throwException(new IllegalStateException(...);
        }
        f.mAdded = true;
        if (mAdded.contains(f)) {
            throw new IllegalStateException("Already added!");
        }
        mAdded.add(f);
    }
} else {
    mAdded = null;
}

(5)恢復(fù)FragmentManagerImpl的mBackStack成員

// FragmentManager # restoreAllState()
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);
        mBackStack.add(bse);
        if (bse.mIndex >= 0) {
            setBackStackIndex(bse.mIndex, bse);
        }
    }
} else {
    mBackStack = null;
}

總結(jié)

對于狀態(tài)保存,在一般情況下,F(xiàn)ragment的狀態(tài)保存屬于FragmentManager的狀態(tài)保存,依靠可序列化的對象FragmentManagerState,將需要保存的信息封裝在內(nèi)并交由系統(tǒng),在配置改變的情況下,F(xiàn)ragment實(shí)例可能直接保存在內(nèi)存中;對于狀態(tài)恢復(fù),保存在內(nèi)存中的實(shí)例和可序列化的FragmentManagerState共同配合,在Activity的onCreate回調(diào)中完成其所管轄的Fragment實(shí)例的狀態(tài)恢復(fù),并在后續(xù)生命周期方法回調(diào)中對Fragment狀態(tài)進(jìn)行轉(zhuǎn)移。


女票良心美代,只做正品的搬運(yùn)工。如果你覺得這篇文章幫助到了你一點(diǎn)點(diǎn),掃碼支持一下吧^ ^


二維碼
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容