Fragment那點事②Fragment生命周期

文章里所有分析都是根據(jù)Android Sdk 25.3.1 v4包

幾種狀態(tài)

Fragment 的狀態(tài) mState 總共有如下幾種:

static final int INITIALIZING = 0;     // Not yet created.
static final int CREATED = 1;          // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3;          // Fully created, not started.
static final int STARTED = 4;          // Created and started, not resumed.
static final int RESUMED = 5;          // Created started and resumed.

mState 的初始狀態(tài)默認為 INITIALIZING ,其實這幾個狀態(tài)的名字和生命周期函數(shù)不是一一對應的,而是在某個狀態(tài)內觸發(fā)一個或多個生命周期函數(shù)。那這幾種狀態(tài)都表示什么意思呢?每種狀態(tài)的過程中又執(zhí)行了什么生命周期函數(shù)呢?由于代碼過多就不貼代碼了,源碼在 FragmentManager.moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) 方法中,請自行查看。該方法中的參數(shù) f 表示要操作的 Fragment,newState 表示要轉換到的目標 state。

INITIALIZING

從后面的注釋可知該狀態(tài)的 Fragment 還沒有創(chuàng)建,當 Fragment 處于這種狀態(tài)的時候 mState = 0 代表要去初始化 Framgent 的一個過程,由源碼可知主要做了如下幾件事情:

  • f.mSavedFragmentState != null 的時候表示這個 Fragment 被 onSaveInstanceState 保存了狀態(tài),這個狀態(tài)包括但不限于:內部 View 的狀態(tài) mSavedViewState、target Fragment 的狀態(tài)、mUserVisibleHint 的狀態(tài),然后取出各狀態(tài)的值賦值給相應屬性。當 f.mUserVisibleHint = false 的時候表示該 Fragment 是不被用戶可見的,所以要讓 Fragment 的狀態(tài)不能超過 STOPPED (已經(jīng)創(chuàng)建但是沒有 started)。

  • mHost、mParentFragment、mFragmentManager 等屬性進行賦值。

  • 觸發(fā) Fragment.onAttach(Context context) 周期函數(shù)和 onAttachFragment(Fragment f) 周期函數(shù)。

  • f.mRetaining 進行判斷,該屬性表示意外重啟時保存了 Fragment 實例,Fragment.mRetainInstance 表示重啟時是否要保存實例,這在后面的 Fragment那點事③保存與恢復 中會有詳細的介紹。當為 true 的時候直接回復 ChildFragment 的SavedState,并把 Fragment 的狀態(tài)修改為 CREATED (已經(jīng)創(chuàng)建)。反之觸發(fā) onCreate(savedInstanceState) 周期函數(shù)并把 Fragment 的狀態(tài)修改為 CREATED (已經(jīng)創(chuàng)建)。

    if (!f.mRetaining) {
      f.performCreate(f.mSavedFragmentState);
      dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
    } else {
      f.restoreChildFragmentState(f.mSavedFragmentState);
      f.mState = Fragment.CREATED;
    }
    
  • 對屬性 f.mFromLayout 進行判斷,該屬性表示 Fragment 是否是在 xml 中直接通過 <fragment/> 聲明的,如果是就直接觸發(fā) onCreateView 周期函數(shù)和 onViewCreated 周期函數(shù)。(大部分情況下都是在代碼中動態(tài)添加 Fragment 的)。

CREATED

該狀態(tài)表示 Fragment 已經(jīng)創(chuàng)建 mState = 1,當 newState > Fragment.CREATED 的時候執(zhí)行如下邏輯:

  • 判斷 f.mFromLayout 屬性,如果不是從 xml 中直接聲明的而是在代碼中動態(tài)添加的(通常都是添加到一個 <FrameLayout/> 載體中),判斷 f.mContainerId 是否等于 0 ,如果不等于說明該載體 ViewGroup 有效并通過 onFindViewById 得到載體 ViewGroup。
  • 觸發(fā) onCreateView 周期函數(shù)返回并賦值給 f.mView 由此可以看出該屬性表示 Fragment 的根 View。
  • 如果 f.mView != null 就賦值給 f.mInnerView 并根據(jù) f.mHidden 屬性判斷是否要隱藏根 View,并觸發(fā)onViewCreated 周期函數(shù)。
  • 觸發(fā) onActivityCreated 周期函數(shù),如果根 View 不等于 null 就調用 f.restoreViewState(f.mSavedFragmentState) 恢復內部 View 的 SavedState。然后把 f.mSavedFragmentState 置空。

ACTIVITY_CREATED

該狀態(tài)表示 Activity 已經(jīng)完成了它的創(chuàng)建過程,此時 mState = 2 。當 newState > ACTIVITY_CREATED 的時候把 Fragment 的狀態(tài)改變?yōu)?STOPPED (已經(jīng)完全創(chuàng)建完畢,但是還沒有 started)。

STOPPED

該狀態(tài)表示 Fragment 已經(jīng)完成了創(chuàng)建過程,但是還沒有 started,此時 mState = 3。當 newState > Fragment.STOPPED 的時候觸發(fā) onStart 周期函數(shù)并將 Fragment 的狀態(tài)改成 STARTED (已經(jīng)創(chuàng)建并且 started 但是還沒有 resumed)。

STARTED

該狀態(tài)表示 Fragment 已經(jīng)創(chuàng)建并且 started 但是還沒有 resumed,此時 mState = 4。當 newState > Fragment.STARTED 觸發(fā) onResume 周期函數(shù),并將 Fragment 的狀態(tài)改變?yōu)?RESUMED (已經(jīng)創(chuàng)建并且 started和 resumed)。

RESUMED

該狀態(tài)表示 Fragment 已經(jīng)創(chuàng)建并且 started和 resumed,此時 mState = 5

逆過程

  1. 當 Fragment 的狀態(tài)為 RESUMED 并且 newState < Fragment.RESUMED 觸發(fā) onPause 周期函數(shù),并將 Fragment 的狀態(tài)改變?yōu)?STARTED 。
  2. 當 Fragment 的狀態(tài)為 STARTED 并且 newState < Fragment.STARTED 觸發(fā) onStop 周期函數(shù),并將 Fragment 的狀態(tài)改為 STOPPED。
  3. 當 Fragment 的狀態(tài)為 STOPPED 并且 newState < Fragment.STOPPED 將 Fragment 狀態(tài)改為ACTIVITY_CREATED 。
  4. 當 Fragment 的狀態(tài)為 ACTIVITY_CREATED 并且 newState < Fragment.ACTIVITY_CREATED 的時候
    • 首先判斷根 Veiw 是否為空,如果不為空時調用 mHost.onShouldSaveFragmentState(f) 方法判斷是否應該保持 Fragment 的狀態(tài)(當 Activity 內存重啟時需要保持狀態(tài))。如果需要保持就調用 saveFragmentViewState 方法進行保存。
    • 觸發(fā) onDestroyView 周期函數(shù),并將 Fragment 的狀態(tài)改為 CREATED
    • 執(zhí)行退出動畫。
    • f.mContainer (載體 ViewGrouop) 中 remove 掉根 View。
  5. 當 Fragment 的狀態(tài)為 CREATED 并且 newState < Fragment.CREATED 當退出動畫執(zhí)行完畢后,判斷屬性 f.mRetaining 當該屬性為 false 的時候說明不需要保存 Fragment 實例,觸發(fā) onDestroy 周期函數(shù),并將 Fragment 的狀態(tài)改為 INITIALIZING 反之說明要保存 Fragment 的實例,直接將 Fragment 的狀態(tài)改為 INITIALIZING。然后觸發(fā) onDetach 周期函數(shù)。如果 keepActive == false 并且 f.mRetaining == false 調用 makeInactive(f) 方法把該 Fragment 從 mActive 列表中移除。

具體示例分析

分析原理從一件具體的事情上去著手去一步步的 debug 能夠產(chǎn)生事半功倍的效果,在 Activity 中添加 Fragment 最典型的步驟就是在 Activity 的 onCreate() 方法中添加如下代碼:

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ordering_bug);
        FragmentManager.enableDebugLogging(true);
        getSupportFragmentManager().beginTransaction()
                .add(R.id.content, a1Fragment)
                .commit();
    }

Fragment 是被添加到 FragmentActivity 中的,Activity 的生命周期決定了被添加的 Fragment 的生命周期。所以從 getSupportFragmentManager() 點進去進入到了 FragmentActivity 類,那就從這里一步步的分析整個流程。

OnCreate()

protected void onCreate(@Nullable Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
      Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
      mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
      // 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]);
          }
        }
      }
    }
  mFragments.dispatchCreate();
}

上面是 onCreate 中關于 Fragment 生命周期的主要代碼,總共干了 3 件事情:

  1. savedInstanceState != null 的時候說明 Activity 被重建,調用 restoreAllState 去執(zhí)行恢復 Fragment 狀態(tài)的流程。
  2. savedInstanceState != null 并且 savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG) 說明 Activity 在被系統(tǒng)銷毀的時候還有沒傳遞回來的 startActivityForResult 回調,把requestCode 和 發(fā)起 fragment 的標識保存在 mPendingFragmentActivityResults 中。
  3. 調用 dispatchCreate() 分發(fā) create() 流程。

mFragments.dispatchCreate()

首先按最簡單的情況分析 Activity 沒有被重建而是第一次啟動,直接調用 mFragments.dispatchCreate() 點開 FragmentController 源碼發(fā)現(xiàn)最終是調用 FragmentManager.dispatchCreate() 方法,在 FragmentManager 中調用 moveToState(Fragment.CREATED, false); 把該 FragmentManager 實例的狀態(tài) mCurState 轉換到 Fragment.CREATED 但是現(xiàn)在還沒有執(zhí)行添加 Fragment 代碼所以 FragmentManager.mActive 為空。然后再執(zhí)行子 Activity onCreate() 方法里的添加 Fragment 的代碼片段,即發(fā)送一個事務消息(添加 Fragment 的代碼片段)到主線程消息隊列中等待執(zhí)行(而不是真正意義上執(zhí)行 add Fragment 的流程)。

onStart()

當調試到下面添加 Fragment 的流程時發(fā)現(xiàn) mManager.mCurState=2 即 FragmentManager 的狀態(tài)現(xiàn)在處于 ACTIVITY_CREATED 即 FragmentActivity 已經(jīng)執(zhí)行到 onStart() 方法了。因為 commit() 是發(fā)送一個消息到主線程等待被執(zhí)行,所以當隊列里的消息被執(zhí)行的時候 FragmentActivity 已經(jīng)執(zhí)行到了 onStart() 方法,如果使用 commitNow() 才是馬上執(zhí)行添加 Fragment 的方法。

// BackStackRecord.executeOps() 部分代碼
if (!mAllowOptimization) {
  // Added fragments are added at the end to comply with prior behavior.
  // 此時 mManager.mCurState = 2
  mManager.moveToState(mManager.mCurState, true);
}

那我們就來分析一下 onStart() 方法驗證前面的猜想。下面是源碼:

@Override
protected void onStart() {
  super.onStart();
  
  mStopped = false;
  mReallyStopped = false;
  mHandler.removeMessages(MSG_REALLY_STOPPED);
  
  if (!mCreated) {
    mCreated = true;
    mFragments.dispatchActivityCreated();
  }
  
  mFragments.noteStateNotSaved();
  mFragments.execPendingActions();

  mFragments.doLoaderStart();

  // NOTE: HC onStart goes here.

  mFragments.dispatchStart();
  mFragments.reportLoaderStart();
}

可以看出在 onStart() 方法中主要做了下面這幾件事情:

  1. 調用 mFragments.dispatchActivityCreated() 分發(fā) ActivityCreated 的事件,通過 FragmentController 調用 FragmentManager 的 dispatchActivityCreated() 方法,在 FragmentManager 中 調用 moveToState(Fragment.ACTIVITY_CREATED, false)() 把 FragmentManager 的狀態(tài)轉換到 ACTIVITY_CREATED ,所以現(xiàn)在 FragmentManager.mCurState = 2。但是現(xiàn)在消息隊列中的添加 Fragment 的代碼片段還沒有被執(zhí)行。

  2. 調用 mFragments.execPendingActions() 通過 FragmentController 調用 FragmentManager 的 execPendingActions() 方法,開始執(zhí)行添加 Fragment 的代碼片段。(關于這里的具體分析請看[Fragment 那點事之① 棧管理)在 FragmentManager.moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) 方法中分別觸發(fā) Fragment.onAttach、

    Fragment.onCreate、Fragment.onCreateViewFragment.onViewCreated、Fragment.onActivityCreated 方法,F(xiàn)ragment 的狀態(tài)現(xiàn)在為 ACTIVITY_CREATED (Activity 已經(jīng)完成了創(chuàng)建過程) 。

  3. 調用 mFragments.dispatchStart() 方法,進而執(zhí)行 FragmentManager.dispatchStart() 方法,在 FragmentManager 中執(zhí)行 moveToState(Fragment.STARTED, false) 。把 FragmentManager 的狀態(tài)轉換到 STARTED ,現(xiàn)在 FragmentManager.mCurState = 4 。該 FragmentManager 管理的 Fragment 的狀態(tài)會變成 STOPPED (即已經(jīng)完全 created 但是還沒有 started 的狀態(tài)) ,然后緊接著就觸發(fā) Fragment.onStart() 方法,F(xiàn)ragment 的狀態(tài)變成 STARTED (已經(jīng)創(chuàng)建并且 started,但是還沒有 resumed)。

onPostResume

@Override
protected void onPostResume() {
  super.onPostResume();
  mHandler.removeMessages(MSG_RESUME_PENDING);
  onResumeFragments();
  mFragments.execPendingActions();
}

在這個方法里調用 onResumeFragments() 通過 FragmentController 向 Fragments 分發(fā) onResume 事件,調用 FragmentManager.dispatchResume() 方法,執(zhí)行 moveToState(Fragment.RESUMED, false) 將 FragmentManager 的狀態(tài)轉換成 RESUMEDFragmentManager.mCurState = 5 。該 FragmentManager 管理的 Fragment 的狀態(tài)也被轉換成了 RESUMED ,并觸發(fā) Fragment.onResume 方法。至此 Fragment 已經(jīng) started 并且resumed。

其余生命周期函數(shù)

其余的生命周期和前面分析的這幾個原理基本一樣,比如 onPause() 時 Fragment 的狀態(tài)為 已經(jīng)完全創(chuàng)建(created)并且 started 但是沒有 resumed 所以通過 FragmentController 分發(fā)把 FragmentManager 管理下的 Fragments 的狀態(tài)都轉化為 STARTED 并且觸發(fā) Fragment.OnPause 方法。

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容