0x00
作為一名 Android 開發(fā)者,大家絕對都接觸過 Fragment 開發(fā),而且絕大多數(shù)人例如我一直都很難記住下圖 Fragment 復(fù)雜的生命周期,更別說要將其與 Activity 的生命周期關(guān)聯(lián)起來。

死背是無法解決問題的,若我們能從源碼的角度對 Fragment 的啟動過程進行分析,就能達到事半功倍的效果。那么我們選擇上圖中的第一部分入手吧。

下面我將會分析 Fragment 這一部分的啟動過程,剩下部分的邏輯沒有多大差異,所用的 Android SDK 版本為 23。
0x01
一般情況下我們 MainActivity 需要顯示一個 ContentFragment,代碼可以這么寫。
//MainActivity
public class MainActivity extends Activity{
ContentFragment mContentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContentFragment = ContentFragment.newInstance(null);
getFragmentManager()
.beginTransaction()
.replace(R.id.container,mContentFragment)
.commit();
}
}
同時為了方便起見,我大概介紹下我們即將遇到的幾個類。第一次看的時候可能印象不深,但沒關(guān)系,后面還會反復(fù)提起。

上面 UML 類圖并不是完整的,但已經(jīng)足夠了。
- ActivityThread : 大名鼎鼎的 Android 入口類,我們的分析也將會從它開始
- Instrumentation : ActivityThread 的得力助手,幫助 ActivityThread 觸發(fā) Activity 的生命周期
- MainActivity : 就是上文提到例子中的 MainActivity 類,繼承自 Activity
- HostCallbacks : Activity 的內(nèi)部類,繼承自 FragmentHostCallback
- FragmentHostCallback : 持有 Handler、FragmentManagerImpl 等等對象的引用,別的對象可以通過持有它的引用間接控制 FragmentManagerImpl 等等對象
- FragmentController : Activity 通過控制它間接向 FragmentManagerImpl 發(fā)出命令
- FragmentManagerImpl : 顧名思義,它繼承自 FragmentManager,用來對 Fragment 進行管理,在 FragmentHostCallback 中被初始化
- BackStackRecord : 繼承自 FragmentTransation 并實現(xiàn)了 Runnable,每次調(diào)用 FragmentManager 對象的
beginTransaction()方法都會產(chǎn)生一個 BackStackRecord 對象,可以將其理解為對 Fragment 的一系列操作(即事務(wù)) - Op : 每次對 Fragment 的操作都會產(chǎn)生一個 Op 對象,其表示雙向鏈表的一個結(jié)點
哈哈,沒印象無所謂...
0x02
那從哪里開始呢,我們注意到 Activity 類中有個 FragmentController 實例,那它是怎么初始化的?我們直接在 Activity 中搜索 FragmentController 關(guān)鍵字,即可找到如下代碼:
//Activity
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
原來在聲明成員變量的同時初始化的呀,那也就是說在 Activity 被實例化時該成員變量也會被初始化,那么 Activity 又是在哪里被實例化的呢?作為一位看過 Activity 啟動過程源碼解析的男人,一下子就能想到 ActivityThread 的 performLaunchActivity 方法(當(dāng)然,沒看過 Activity 啟動過程源碼的朋友也沒事,這篇文章分析的流程比那個簡單多了,而且我們這里并不關(guān)注 Activity 的啟動過程,看了這個或許對看那個有一定幫助),那我們?nèi)?ActivityThread 類的 performLaunchActivity 方法找下吧
//ActivityThread
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
/*這個方法最終會通過反射調(diào)用 Activity 的無參構(gòu)造方法*/
//...
} catch (Exception e) {
//...
}
//上面代碼省略了一些非本次該關(guān)注的邏輯,下同
我們從 Activity 的實例化這里開始講起吧
0x03
上文說到,Activity 會在 ActivityThread 的方法 performLaunchActivity 中通過反射實例化,相當(dāng)于調(diào)用了它的無參構(gòu)造方法,接著會觸發(fā) Activity 的成員變量 mFragments 的初始化,即
//Activity
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
直接實例化了一個 HostCallbacks 對象并將其作為參數(shù)傳入 FragmentController 類的 createController 靜態(tài)方法中。
I
好的,我們先看看 HostCallbacks 初始化做了啥。
//HostCallbacks(因為 HostCallbacks 是 Activity 的內(nèi)部類,所以是在 Activity.java 文件里)
public HostCallbacks() {
super(Activity.this );
}
嗯,因為 HostCallbacks 是 Activity 的內(nèi)部類,所以直接用 Activity.this 作為參數(shù)調(diào)用它父類的構(gòu)造方法,通過上文我們知道它的父類是 FragmentHostCallback
//FragmentHostCallback
FragmentHostCallback(Activity activity) {
this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
}
FragmentHostCallback(Activity activity, Context context, Handler handler,
int windowAnimations) {
mActivity = activity;
mContext = context;
mHandler = handler;
mWindowAnimations = windowAnimations;
}
我們可以了解到它最終調(diào)用了 FragmentHostCallback 四個參數(shù)的重載構(gòu)造方法,并會將 Activity 、Handler 等等對象保存到它的成員變量中。上文說到 FragmentManagerImpl 會在 FragmentHostCallback 中被初始化,看來它不是在構(gòu)造方法中被初始化,那我們到成員變量的聲明處看看吧。
//FragmentHostCallback
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
又是在聲明的同時初始化。FragmentManagerImpl 繼承自抽象類 FragmentManager,F(xiàn)ragmentManagerImpl 采用的是默認的構(gòu)造方法,所以這部分的分析就到此為止了。對了,F(xiàn)ragmentManagerImpl 和 FragmentManager 兩個類都是在 FragmentManager.java 文件中的,而且不是內(nèi)外部類關(guān)系,F(xiàn)ragmentManagerImpl 類的聲明如下
//FragmentManager
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2{
//...
}
作用域是包級的,包名是 android.app。
II
上一節(jié)后我們已經(jīng)有了一個 HostCallback 對象,并將其作為參數(shù)傳給 FragmentController 的 createController 靜態(tài)方法,我們現(xiàn)在進去看看吧。
//FragmentController
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
private FragmentController(FragmentHostCallback<?> callbacks) {
mHost = callbacks;
}
原來 FragmentController 隱藏了自己的構(gòu)造方法,createController 就如同工廠方法,最后令 FragmentController 對象持有了 HostCallbacks 對象的引用。這樣 FragmentController 就能通過 HostCallbacks 對象的引用來間接調(diào)用 FragmentManagerImpl 了啦,因為你看上面 FragmentHostCallback 類中 mFragmentManager 的聲明也是默認包級的。
階段小結(jié)
在 Activity 實例化的過程中,初始化了它的成員變量 FragmentController,F(xiàn)ragmentController 持有了 HostCallbacks 對象的引用,HostCallbacks 是 Activity 的內(nèi)部類,HostCallbacks 用 Activity 對象作為參數(shù)調(diào)用自己父類 FragmentHostCallback 的構(gòu)造方法,接著 FragmentHostCallback 會持有了 Activity、Handler 等等對象的引用,并在聲明 mFragmentManager 成員變量的同時實例化 FragmentManagerImpl 對象。
0x04
在 ActivityThread 類的 performLounchActivity 方法里 Activity 被實例化后不久會被調(diào)用重量級的 attach 方法,我們試試到這方法下看看是否有我們需要的信息。
//Activity
mFragments.attachHost(null /*parent*/);
我們知道 mFragments 就是 FragmentController 對象的引用,看來這里確實有些初始化操作,那為什么是傳入 null 呢?我們看下方法吧。
//FragmentManagerImpl
public void attachHost(Fragment parent) {
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
因為 Fragment 下也能有自己的子 Fragment,而現(xiàn)在我們的 Fragment 是在 Activity 下的,所以這里當(dāng)然就直接傳入 null 啦。我們再注意到本方法調(diào)用了 mHost 的 mFragmentManager 成員變量的 attachController 方法,我們只需關(guān)心方法的第一個參數(shù)。
//FragmentManagerImpl
public void attachController(FragmentHostCallback<?> host, FragmentContainer container,
Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
}
嗯,現(xiàn)在 FragmentManagerImpl 對象也持有了 HostCallbacks 對象的引用。
階段小結(jié)
這一部分我們關(guān)注的僅僅是 FragmentManagerImpl 對象持有了 HostCallbacks 對象的引用。
0x05
我們知道 Fragment 的生命周期與 Acitivty 的有對應(yīng)關(guān)系,那么我們也就可以猜到 Activity 的生命周期方法被觸發(fā)時,Activity 會同時觸發(fā) Fragment 對應(yīng)的生命周期方法,而且是通過自己持有的 FragmentController 對象來觸發(fā)的,我們來看看是不是這樣子吧。Activity 生命周期第一個被調(diào)用的方法是 onCreate 方法,它是在哪里被觸發(fā)的呢?現(xiàn)在就是 ActivityThread 的得力助手 Instrumentation 出場的時候了!
還是在 ActivityThread 的 performLounchActivity 方法中,我們發(fā)現(xiàn)如下代碼
//ActivityThread
mInstrumentation.callActivityOnCreate(activity, r.state);
跳去 Instrumentation 類看看
//Instrumentation
public void callActivityOnCreate(Activity activity, Bundle icicle) {
//...
activity.performCreate(icicle);
//...
}
調(diào)用了 performCreate 方法,注意這里的 activity 的運行時類型是 MainActivity,因為我們的 MainActivity 繼承了 Activity,但 performCreate 方法是 final 的,MainActivity 無法重寫,所以調(diào)用了其父類 Activity 的 performCreate 方法,我們?nèi)タ聪?/p>
//Activity
final void performCreate(Bundle icicle) {
onCreate(icicle);
//...
performCreateCommon();
}
先調(diào)用 onCreate方法再調(diào)用 performCreateCommon方法,同時我們注意到 onCreate 方法最先被調(diào)用而 performCreateCommon 最后被調(diào)用,兩個方法都會分別觸發(fā) Fragment 的生命周期方法,這樣安排是有目的的。下面我們分別分析。
PS : 下面是一連串的調(diào)用,先休息下,揉揉眼睛,喝喝水吧。
I
因為 MainActivity 重寫了 Activity 的 onCreate 方法,我們先再看下我們重寫的 onCreate 方法。
//MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContentFragment = ContentFragment.newInstance(null);
getFragmentManager()
.beginTransaction()
.replace(R.id.container,mContentFragment)
.commit();
}
這個方法做了挺多操作的,我們還是一個一個來哈。
I-I
首先調(diào)用了父類 Activity 的 onCreate 方法,我們?nèi)タ纯醋隽松丁?/p>
//Activity
@MainThread
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
//...
mFragments.dispatchCreate();
//...
}
Activity 好懶喲,又讓人家 FragmentController 干活,可憐的 FragmentController
//FragmentController
public void dispatchCreate() {
mHost.mFragmentManager.dispatchCreate();
}
FragmentController 深得 Activity 精髓,把活推給了 FragmentManagerImpl,原來 FragmentManagerImpl 才是苦力。
//FragmentManagerImpl
public void dispatchCreate() {
//...
moveToState(Fragment.CREATED, false);
}
void moveToState(int newState, boolean always) {
moveToState(newState, 0, 0, always);
}
void moveToState(int newState, int transit, int transitStyle, boolean always) {
if (mHost == null && newState != Fragment.INITIALIZING) {
throw new IllegalStateException("No activity");
}
if (!always && mCurState == newState) {
return;
}
mCurState = newState;
if (mActive != null) {
//...
}
}
上面有三個方法被順序調(diào)用,到了最后一個 moveToState 方法時我們只需關(guān)注它的參數(shù) newState = Fragment.CREATED、always = false,而默認情況下成員變量 mCurState = Fragment.INITIALIZING、mActive = null,所以該方法執(zhí)行后只有一個值得我們關(guān)注的細節(jié) mCurState = Fragment.CREATED 了
I-II
MainActivity 的父類的 onCreate 方法執(zhí)行完后我們該關(guān)注 getFragmentManager 方法了,到 Activity 中看看這個方法吧。
//Activity
public FragmentManager getFragmentManager() {
return mFragments.getFragmentManager();
}
//FragmentController
public FragmentManager getFragmentManager() {
return mHost.getFragmentManagerImpl();
}
只是直接返回 HostCallbacks 對象持有的 FragmentManagerImpl 對象而已。
I-III
接下來就到了 FragmentManagerImpl 的 beginTransaction 方法了。
//FragmentManagerImpl
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
如我們所知,BackStackRecord 對象代表一系列對 Fragment 的操作,即事務(wù),這里調(diào)用了 BackStackRecord 的構(gòu)造方法并將 FragmentManagerImpl 自己作為參數(shù)傳入。咱去看看構(gòu)造方法做了啥。
//BackStackRecord
public BackStackRecord(FragmentManagerImpl manager) {
mManager = manager;
}
這樣 BackStackRecord 也持有了 FragmentManagerImpl 對象的引用。
I-Ⅳ
然后調(diào)用 BackStackRecord 的 replace 方法,即
//BackStackRecord
public FragmentTransaction replace(int containerViewId, Fragment fragment) {
return replace(containerViewId, fragment, null);
}
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
if (containerViewId == 0) {
throw new IllegalArgumentException("Must use non-zero containerViewId");
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
先調(diào)用 replace 兩個參數(shù)的重載方法,在該方法里調(diào)用了 replace 三個參數(shù)的重載方法,同時參數(shù) tag = null,在這個方法里首先判斷傳進的用來裝載 Fragment 的容器的 ID 是否有效,接著調(diào)用 doAddOpp 方法,它第三個參數(shù)傳入了的是 OP_REPLACE 常量。這里注意它最后返回了 this,也就是我們的鏈式調(diào)用的下一個方法還是 BackStackRecord 對象的,結(jié)合下面我們腦海就能很形象地產(chǎn)生 Op 雙向鏈表的圖像。
//BackStackRecord
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
if (tag != null) {
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment "
+ fragment + ": was " + fragment.mTag
+ " now " + tag);
}
fragment.mTag = tag;
}
if (containerViewId != 0) {
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
在本方法首先讓參數(shù) fragment 持有 FragmentManagerImpl 的引用,接著就是判斷參數(shù) tag 和 containerViewId 是否有效并賦值給 fragment 的成員變量。最后 Op 對象終于出場了(此處應(yīng)有掌聲)。實例化了一個 OP 對象后改變了它成員變量 cmd 的值,這里是 OP_REPLACE,接著讓 Op 也持有 Fragment 對象的引用,最后就是將 Op 對象作為參數(shù)調(diào)用 addOp 方法。
//BackStackRecord
void addOp(Op op) {
if (mHead == null) {
mHead = mTail = op;
} else {
op.prev = mTail;
mTail.next = op;
mTail = op;
}
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
mNumOp++;
}
前面我們說過 Op 表示的是雙向鏈表的一個結(jié)點,這里得到了證實。這個方法只是雙向鏈表的創(chuàng)建及添加結(jié)點邏輯。
I-V
可以提交事務(wù)了,即調(diào)用了 BackStackRecord 對象的 commit 方法。
//BackStackRecord
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) {
throw new IllegalStateException("commit already called");
}
//...
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
最終調(diào)用了 commitInternal 方法,首先通過 mCommitted 判斷是否已經(jīng)提交過,因為默認為 false,所以這里不會拋出錯誤,接著最重要的邏輯就是調(diào)用了 mManager.enqueueAction(this, allowStateLoss),mManager 就是FragmentManagerImpl 對象,方法 enqueueAction 的第一個參數(shù)是 Runnable 類,但這里的 this 不是 BackStackRecord 對象么?
//BackStackRecord
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, Runnable{
//...
}
看到了吧,BackStackRecord 實現(xiàn)了 Runnable,看來會有大事發(fā)生...
//FragmentManagerImpl
public void enqueueAction(Runnable action, boolean allowStateLoss) {
//...
synchronized (this) {
if (mDestroyed || mHost == null) {
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<Runnable>();
}
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
這里將 Runnable 裝入了 mPendingActions 中,因為此時 mPendingActions.size() == 1 為 true,所以最終會將 mExecCommit 成員變量壓入 mHost 持有的來自 Activity 的 Handler 對象里。那么我們現(xiàn)在可以推斷出 mExecCommit 也是 Runnable 類型,同時它會在主線程被調(diào)用。我們看看 mExecCommmit 是何方神圣。
//FragmentManagerImpl
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
原來它的作用就是為了切換到主線程然后執(zhí)行它外部類即 FragmentManagerImpl 的 execPendingActions 方法而已?,F(xiàn)在我假設(shè)這個 Runnable 對象會被馬上被調(diào)用,實際可能需要排隊...好,到 execPendingAcions 方法了。
//FragmentManagerImpl
public boolean execPendingActions() {
//...
while (true) {
int numActions;
synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
break;
}
numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
}
mPendingActions.toArray(mTmpActions);
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
//...
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
mTmpActions[i] = null;
}
//...
}
//...
}
本方法我們只需關(guān)注首先將 mPendingActions 里的 Runnable 對象轉(zhuǎn)移到 mTmpActions 數(shù)組里,并依次調(diào)用 mTmpActions 數(shù)組保存的 Runnable 的 run 方法。我們知道這里指的就是 BackStackRecord 中的 run 方法。去看看吧
//BackStackRecord
public void run() {
//...
Op op = mHead;
while (op != null) {
switch (op.cmd) {
//...
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
//...
if (f != null) {
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
}
break;
//...
}
op = op.next;
}
mManager.moveToState(mManager.mCurState, mTransition,mTransitionStyle, true);
//...
}
這個方法其實很長的,但我們還是只要關(guān)注我們當(dāng)前需要關(guān)注的邏輯就行啦。可以看到其實就是從頭遍歷 Op 雙向鏈表,并通過判斷 Op 對象里的 cmd 成員變量的值進行不同操作而已(其實這就是命令模式,可以看我的另一篇介紹設(shè)計模式的文章),這里我們只關(guān)注 OP_REPLACE。首先取出 Op 中保存的 Fragment 對象作為參數(shù)調(diào)用 FragmentManagerImpl 對象的 addFragment 方法,最后又通過 FragmentManagerImpl 對象的 moveToState 方法改變狀態(tài),還是一步一步來。
PS : 咳咳,下面我還有幾句話要說。哈哈,我畫了張思維導(dǎo)圖,或許對照著看能更好地理解。
先看看 FragmentManagerImpl 的 addFragment 方法吧,注意這里第一個參數(shù)傳入了 Fragment 對象,第二個參數(shù)傳入 false。
//FragmentManagerImpl
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
//...
makeActive(fragment);
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
mAdded.add(fragment);
fragment.mAdded = true;
fragment.mRemoving = false;
//...
if (moveToStateNow) {
moveToState(fragment);
}
}
}
這里做了幾件事:
- 通過
makeActive方法將 Fragment 對象添加進 mActive 列表中。 - 將 Fragment 添加進 mAdded 列表中。
- 設(shè)置 Fragment 的一些屬性。
然后到 FragmentManagerImpl 的 moveToState 方法了。我們只需關(guān)心它的第一個參數(shù),即 mManager.mCurState,我們知道這里的 mCurState 此時已經(jīng)被賦值成了 Fragment.CREATED。
//FragmentManagerImpl
void moveToState(int newState, int transit, int transitStyle, boolean always) {
//...
mCurState = newState;
if (mActive != null) {
//..
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null) {
moveToState(f, newState, transit, transitStyle, false);
//...
}
}
//...
}
}
這里做了兩件事
- 雖然 mCurState 已經(jīng)是 Fragment.CREATED 了,還是被再次賦了一次 Fragment.CREATED 值。(當(dāng)然不是多余,這次只不過是特殊而已啦)
- 和上次不同,這次 mActive 是非空的,那就遍歷 mActive 取出 Fragment 作為參數(shù)并調(diào)用另一個
moveToState方法。下面我們見識下這個方法吧(<- 大 BOSS)。方法很長,還是只關(guān)注我們需要那部分。
//FragmentManagerImpl
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
//...
if (f.mState < newState) {
//...
switch (f.mState) {
case Fragment.INITIALIZING:
//...
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
f.mCalled = false;
f.onAttach(mHost.getContext());
//...
if (f.mParentFragment == null) {
mHost.onAttachFragment(f);
}
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
}
f.mRetaining = false;
if (f.mFromLayout) {
//...
}
//...
}
f.mState = newState;
}
首先注意這里 f.mState = Fragment.INITIALIZING(默認)、newState = Fragment.CREATED、mParent = null、f.mRetaining = false(默認)、f.mFromLayout = false(默認)。那么這里干了幾件事。
- Fragment 獲得了 HostCallbacks 對象的引用。
- Fragment 再次獲得 FragmentManagerImpl 的引用。
- 調(diào)用了 Fragment 生命周期的第一個方法
onAttach??! - 因為 f.mParentFragment == null 為 true,所以會調(diào)用 mHost 的
onAttachFragment,進去看看
//HostCallback
@Override
public void onAttachFragment(Fragment fragment) {
Activity.this.onAttachFragment(fragment);
}
也就說 Activity 可以通過這個方法知道被依附的 Fragment 的實例。
- 因為 !f.mRetaining 為 true,所以會接著調(diào)用 Fragment 的
performCreate方法
//Fragment
void performCreate(Bundle savedInstanceState) {
//...
onCreate(savedInstanceState);
//...
}
這里終于調(diào)用了 Fragment 的生命周期 onCreate 方法??!
- 方法最后改變了 Fragment 的狀態(tài),即 f.mState = newState = Fragment.CREATED。
- 有個容易忽略的細節(jié)就是,在每個 case 塊的最后是沒有 break 關(guān)鍵字的(可不是我忽略掉的喔,你看之前那 switch 塊就有 break 關(guān)鍵字),也就是說只要符合條件會繼續(xù)到下一個 case 塊執(zhí)行。
I-小結(jié)
在 Activity 的 performCreate 方法中調(diào)用了 onCreate 方法后,做了如上操作。主要做了兩件最關(guān)注的事:
- 改變了 FragmentManagerImpl 的 mCurState 為 Fragment.CREATED。
- 先切換到主線程后先后調(diào)用了 Fragment 的生命周期方法
onAttach、onCreate并將 Fragment 的狀態(tài)即 mState 改為了 Fragment.CREATED。
II
那么就到了 Activity 的 performCreate 方法中最后調(diào)用的 performCreateCommon 方法了。
//Activity
final void performCreateCommon() {
//...
mFragments.dispatchActivityCreated();
//...
}
和上面一樣,相同的邏輯,那么我們可以猜到下面其實也大同小異,那就全盤托出吧。
//ActivityController
public void dispatchActivityCreated() {
mHost.mFragmentManager.dispatchActivityCreated();
/*一樣,調(diào)用了 FragmentManagerImpl 的 dispatchActivityCreated 方法*/
}
//FragmentManagerImpl
public void dispatchActivityCreated() {
//...
moveToState(Fragment.ACTIVITY_CREATED, false);
/*現(xiàn)在傳入的狀態(tài)常量是 Fragment.ACTIVITY_CREATED*/
}
//FragmentManagerImpl
void moveToState(int newState, boolean always) {
moveToState(newState, 0, 0, always);
}
//FragmentManagerImpl
void moveToState(int newState, int transit, int transitStyle, boolean always) {
//...
/*mCurState 這里又被改成了 Fragment.ACTIVITY_CREATED*/
mCurState = newState;
if (mActive != null) {
//...
for (int i=0; i<mActive.size(); i++) {
/*一樣,遍歷 mActive,調(diào)用 moveToState,分別將 Fragment 作為參數(shù)傳入 */
Fragment f = mActive.get(i);
if (f != null) {
moveToState(f, newState, transit, transitStyle, false);
//...
}
}
//...
}
}
//FragmentManagerImpl
//方法很長,不怕,我們在代碼外分析
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
//...
if (f.mState < newState) {
//...
switch (f.mState) {
//...
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
//...
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
//...
}
}
f.mContainer = container;
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
//...
if (container != null) {
Animator anim = loadAnimator(f, transit, true,
transitionStyle);
if (anim != null) {
anim.setTarget(f.mView);
setHWLayerAnimListenerIfAlpha(f.mView, anim);
anim.start();
}
container.addView(f.mView);
}
//...
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
f.performActivityCreated(f.mSavedFragmentState);
//...
}
//...
}
}
f.mState = newState;
}
嗯,和我們猜的一樣,最后還是調(diào)用了這個 moveToState 方法,因為現(xiàn)在我們的參數(shù) newState = Fragment.ACTIVITY_CREATED、f.newState = Fragment.CREATED、f.mFromLayout = false(默認),那從代碼一步一步來看這里做了幾件事。
- 通過 ID 取出裝載 Fragment 的容器并賦給 container(看到這里是不是很激動)
- 通過調(diào)用
f.performCreateView獲取到 View 并賦給 f.mView,那么performCreateView又是何方神圣?
//Fragment
View performCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//...
return onCreateView(inflater, container, savedInstanceState);
}
哈哈,調(diào)用了我們 Fragment 的生命周期方法 onCreateView 方法?。?/p>
- 然后當(dāng)然是分別判斷 f.mView、container 是否為非空以及是否有動畫,有動畫的話就啟動動畫,可以看到,這里是屬性動畫。最后就將 f.mView 添加到 container 中啦。
- 我們下一個生命周期方法就要來啦,去看看
f.performActivityCreated
//Fragment
void performActivityCreated(Bundle savedInstanceState) {
//...
onActivityCreated(savedInstanceState);
//...
}
onActivityCreated 終于出現(xiàn)啦,就這樣,我們需要分析的生命周期方法都出來啦。
- 方法最后一樣改變了 Fragment 的狀態(tài),這次是 f.mState = newState = Fragment.ACTIVITY_CREATED
II-小結(jié)
通過 Activity 的 performCreateCommon 方法后,做了這么兩件事:
- 改變了 FragmentManager 的 mCruState 為 Fragment.ACTIVITY_CREATED。
- 接著 Fragment 的生命周期方法
onCreateView被調(diào)用后將返回的 View 添加到指定容器中,隨后就是另一個生命周期方法onActivityCreated方法,最后一樣還會將 f.mState 改成最新的狀態(tài)即 Fragment.ACTIVITY_CREATED。
階段小結(jié)
InStrumentation 對象通過 callActivityOnCreate 方法觸發(fā)了 Activity 的 performCreate 后,Activity 也負責(zé)任地分別觸發(fā)了 Fragment 的生命周期方法 onAttach、onCreate、onCreateView、onActivityCreated。經(jīng)過了上面的分析,現(xiàn)在看這張圖是不是不會覺得難記了?

其它生命周期方法邏輯沒多大區(qū)別,每當(dāng) Activity 的生命周期方法被觸發(fā)后它也會觸發(fā)依附在它身上的 Fragment 的生命周期方法,感興趣的朋友可以親自去看看源碼。
0x06
為了方便理解,我畫了張思維導(dǎo)圖,圖片在此(超級大...)。

我再放上最開始那張類圖,現(xiàn)在再看一遍,不知是不是印象深刻多了?

0x07
我看過很多作者寫的源碼解析,但這次是我第一次寫源碼解析,不知自己能否駕馭得當(dāng),不知能否讓各位理解整個流程。如有不足,希望能在評論提出,十分感謝哈。如果覺得寫得不錯,不求打賞,能否稍微給我點個贊呢?