Android 中Fragment的自動重建

Fragment常見的兩種重建方式,一種是經過調用setRetainInstance來通知系統在重建Activity(例如屏幕配置改變)時保留此Fragment;另外一種方式是系統在重建Activity時自動重建Fragment,典型例子是FragmentActivity對管理的Fragment的重建。android

setRetainInstance

直接參考官方文檔的解釋:bash

Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:app

  • onDestroy() will not be called (but onDetach() still will be, because the fragment is being detached from its current activity).
  • onCreate(android.os.Bundle) will not be called since the fragment is not being re-created.
  • onAttach(android.app.Activity) and onActivityCreated(android.os.Bundle) will still be called.

調用了此方法後,Activity被銷燬時,此Fragment會被保留(進程不消亡的前提下),Activity重建時,Fragment直接掛載。ide

原理:當配置發生變化時,Activity進入銷燬過程,FragmentManager先銷燬隊列中Fragment的視圖,而後檢查每一個Fragment的retainInstance屬性。若是retainInstance爲false,FragmentManager會銷燬該Fragment實例;若是retainInstance爲true,則不會銷燬該Fragment實例,Activity重建後,新的FragmentManager會找到保留的Fragment併爲其建立視圖。spa

FragmentActivity對Fragment的重建

FragmentActivity在配置改變被銷燬時,FragmentManager中的Fragment狀態會被保存下來,等以後Activity重建時,被銷燬的Fragment也會被重建。因此在這種狀況下,Activity重建時,不須要再在onCreate中建立新的Fragment,而是使用被自動重建的Fragment(能夠經過tag找到)。Fragment的狀態保存及重建過程能夠在FragmentActivity的代碼中查看。rest

當配置改變,Activity即將銷燬時,FragmentActivity會先保存全部隊列中的Fragment狀態。code

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        markFragmentsCreated();
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
複製代碼

mFragments爲FragmentManager的引用,FragmentManager.saveAllState返回一個包含須要保存的Fragment的Parcelable,此數據以後會用於重建這些Fragment。隊列

查看FragmentManager.saveAllState方法的實現,能夠看出返回的Parcelable實際爲一個FragmentManagerState實例,該類的數據成員定義爲:進程

final class FragmentManagerState implements Parcelable {
    FragmentState[] mActive;
    int[] mAdded;
    BackStackState[] mBackStack;
    int mPrimaryNavActiveIndex = -1;
    int mNextFragmentIndex;
}
複製代碼

FragmentState的數據成員:文檔

final class FragmentState implements Parcelable {
    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;
    final boolean mHidden;

    Bundle mSavedFragmentState;

    Fragment mInstance;
}
複製代碼

FragmentState包含描述Fragment的各個數據變量,足夠從零從新建立一個被銷燬的Fragment。

在保存了Fragment數據以後,Activity實例以及沒有調用setRetainInstance(true)的Fragment實例都被銷燬。

而當Activity重建時,被銷燬的Fragment也會被重建:

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

        super.onCreate(savedInstanceState);

        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            mViewModelStore = nc.viewModelStore;
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
複製代碼

FragmentActivity經過調用FragmentManager的restoreAllState方法,重建以前保存下來並被銷燬的Fragment。

相關文章
相關標籤/搜索