文章里所有分析都是根據(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 。
逆過程
- 當 Fragment 的狀態(tài)為 RESUMED 并且
newState < Fragment.RESUMED觸發(fā) onPause 周期函數(shù),并將 Fragment 的狀態(tài)改變?yōu)?STARTED。 - 當 Fragment 的狀態(tài)為 STARTED 并且
newState < Fragment.STARTED觸發(fā) onStop 周期函數(shù),并將 Fragment 的狀態(tài)改為STOPPED。 - 當 Fragment 的狀態(tài)為 STOPPED 并且
newState < Fragment.STOPPED將 Fragment 狀態(tài)改為ACTIVITY_CREATED。 - 當 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。
- 首先判斷根 Veiw 是否為空,如果不為空時調用
- 當 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 件事情:
- 當
savedInstanceState != null的時候說明 Activity 被重建,調用restoreAllState去執(zhí)行恢復 Fragment 狀態(tài)的流程。 - 當
savedInstanceState != null并且savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)說明 Activity 在被系統(tǒng)銷毀的時候還有沒傳遞回來的startActivityForResult回調,把requestCode和 發(fā)起 fragment 的標識保存在mPendingFragmentActivityResults中。 - 調用
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() 方法中主要做了下面這幾件事情:
調用
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í)行。-
調用
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.onCreateView、Fragment.onViewCreated、Fragment.onActivityCreated方法,F(xiàn)ragment 的狀態(tài)現(xiàn)在為ACTIVITY_CREATED(Activity 已經(jīng)完成了創(chuàng)建過程) 。 調用
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)轉換成 RESUMED 即 FragmentManager.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 方法。