注意:文章對(duì)Fragment源碼的分析基于support v4的Fragment包扫外,版本號(hào)為25.3.1
Fragment相關(guān)類(lèi)UML圖
support包中對(duì)負(fù)責(zé)管理Fragment生命是FragmentActivity债沮,v7包的AppCompatActivity也是繼承于它终议。
FragmentActivity管理Fragment是通過(guò)它內(nèi)部mFragments的變量,mFragments類(lèi)型為FragmentController.
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
FragmentActivity傳遞自身生命狀態(tài)难衰、狀態(tài)保存、恢復(fù)都是通過(guò)調(diào)用mFragments相應(yīng)的方法進(jìn)行處理;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
//...
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
//...
mFragments.dispatchCreate();
}
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
而FragmentController本身只是簡(jiǎn)單的將相應(yīng)請(qǐng)求轉(zhuǎn)發(fā)給FragmentManagerImpl岂津,只是起到了橋梁溝通作用。
FragmentActivity創(chuàng)建mFragments時(shí)傳遞了一個(gè)HostCallbacks內(nèi)部類(lèi)實(shí)例悦即,這個(gè)callback對(duì)象給Fragment提供了獲取Context吮成,啟動(dòng)Activity的能力。
Fragment
Fragment主要是由Attr盐欺、View赁豆、State構(gòu)成,
Attr:固有屬性冗美,F(xiàn)ragment基本信息魔种,基本不會(huì)隨生命周期變化。
Bundle mArguments; //構(gòu)造參數(shù)
boolean mFromLayout; //是否從layout文件中創(chuàng)建
String mTag;
...
View:Fragment管理View所依賴(lài)的相關(guān)成員變量粉洼。
// The parent container of the fragment after dynamically added to UI.
ViewGroup mContainer;
// The View generated for this fragment.
View mView;
// The real inner view that will save/restore state.
View mInnerView;
State:Fragment的狀態(tài)节预,管理Fragment的顯示、生命周期属韧。
int mState = INITIALIZING; //生命周期狀態(tài)
boolean mAdded; //是否被添加
boolean mRemoving; //是否被移除
boolean mHidden;// 是否被隱藏
boolean mDetached; //是否已經(jīng)分離
// 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.
Fragment的生命周期方法安拟,onAttach, onCreate, onCreateView...都是在mState狀態(tài)變化中進(jìn)行回調(diào)的。
Fragment的事務(wù):FragmentTransaction宵喂、BackStackRecord
添加一個(gè)Fragment糠赦,我們一般使用如下代碼:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.contaniner, fragment);
transaction.commit();
FragmentTransaction表示一個(gè)事務(wù),提供了如add锅棕、remove拙泽、attach、detach裸燎、show顾瞻、hide、replace等接口操控Fragment德绿。它的具體實(shí)現(xiàn)類(lèi)是BackStackRecord荷荤,它的接口實(shí)現(xiàn)如下:
@Override
public FragmentTransaction add(Fragment fragment, String tag) {
doAddOp(0, fragment, tag, OP_ADD);
return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
...
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
void addOp(Op op) {
mOps.add(op);
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
}
@Override
public FragmentTransaction remove(Fragment fragment) {
Op op = new Op();
op.cmd = OP_REMOVE;
op.fragment = fragment;
addOp(op);
return this;
}
...
可以看到我們調(diào)用的add、remove等方法最后都是生成一個(gè)Op對(duì)象保存在mOps列表中移稳,Op是Operator簡(jiǎn)寫(xiě)表示操作蕴纳,Op的cmd屬性則區(qū)分操作的類(lèi)型,cmd的值取如下幾種:
static final int OP_NULL = 0;
static final int OP_ADD = 1;
static final int OP_REPLACE = 2;
static final int OP_REMOVE = 3;
static final int OP_HIDE = 4;
static final int OP_SHOW = 5;
static final int OP_DETACH = 6;
static final int OP_ATTACH = 7;
上面操作完畢后个粱,最后是commit事務(wù)了
@Override
public int commit() {
return commitInternal(false);
}
@Override
public int commitAllowingStateLoss() {
return commitInternal(true);
}
@Override
public void commitNow() {
...
// 直接開(kāi)始執(zhí)行事務(wù)
mManager.execSingleAction(this, false);
}
@Override
public void commitNowAllowingStateLoss() {
...
// 直接開(kāi)始執(zhí)行事務(wù)
mManager.execSingleAction(this, true);
}
int commitInternal(boolean allowStateLoss) {
...
// 事務(wù)入對(duì)象古毛,等待下一個(gè)Handler回調(diào)執(zhí)行
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
*AllowingStateLoss表示是否允許狀態(tài)丟失,如果不允許但是當(dāng)前Activity狀態(tài)已經(jīng)觸發(fā)保存了調(diào)用會(huì)拋出異常几蜻;commit喇潘、commitNow的區(qū)別則是提交事務(wù)等待下個(gè)主線(xiàn)程Handler回調(diào)執(zhí)行還是立即執(zhí)行体斩,除了執(zhí)行時(shí)機(jī)不一樣外,兩者最后觸發(fā)的事務(wù)執(zhí)行邏輯是一樣的颖低。
事務(wù)執(zhí)行邏輯依然在BackStackRecord中:
void executeOps() {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.fragment;
f.setNextTransition(mTransition, mTransitionStyle);
switch (op.cmd) {
case OP_ADD:
f.setNextAnim(op.enterAnim);
mManager.addFragment(f, false);
break;
case OP_REMOVE:
f.setNextAnim(op.exitAnim);
mManager.removeFragment(f);
break;
case OP_HIDE:
f.setNextAnim(op.exitAnim);
mManager.hideFragment(f);
break;
case OP_SHOW:
f.setNextAnim(op.enterAnim);
mManager.showFragment(f);
break;
case OP_DETACH:
f.setNextAnim(op.exitAnim);
mManager.detachFragment(f);
break;
case OP_ATTACH:
f.setNextAnim(op.enterAnim);
mManager.attachFragment(f);
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
if (!mAllowOptimization && op.cmd != OP_ADD) {
mManager.moveFragmentToExpectedState(f);
}
}
if (!mAllowOptimization) {
// Added fragments are added at the end to comply with prior behavior.
mManager.moveToState(mManager.mCurState, true);
}
}
執(zhí)行邏輯是遍歷所有添加的操作絮吵,執(zhí)行相應(yīng)的FragmentManage方法,最后將Fragment的狀態(tài)移動(dòng)的相應(yīng)的狀態(tài)忱屑。
Fragment狀態(tài)變遷:moveToState
Fragment添加到FragmentMange中后蹬敲,要將它移動(dòng)到相應(yīng)的狀態(tài),使Fragment正確的顯示莺戒、交互伴嗡。
FragmentManage的成員變量mCurState存儲(chǔ)著當(dāng)前Activity狀態(tài)對(duì)應(yīng)的Fragment狀態(tài)值,它的取值范圍如同F(xiàn)ragment从铲。Activity的狀態(tài)發(fā)生變化時(shí)都會(huì)觸發(fā)相應(yīng)方法修改mCurState瘪校,并將所有的active 的Fragment移動(dòng)到相應(yīng)的狀態(tài)上。
public void dispatchCreate() {
mStateSaved = false;
moveToState(Fragment.CREATED, false);
}
public void dispatchActivityCreated() {
mStateSaved = false;
moveToState(Fragment.ACTIVITY_CREATED, false);
}
public void dispatchStart() {
mStateSaved = false;
moveToState(Fragment.STARTED, false);
}
public void dispatchResume() {
mStateSaved = false;
moveToState(Fragment.RESUMED, false);
}
public void dispatchPause() {
moveToState(Fragment.STARTED, false);
}
public void dispatchStop() {
// See saveAllState() for the explanation of this. We do this for
// all platform versions, to keep our behavior more consistent between
// them.
mStateSaved = true;
moveToState(Fragment.STOPPED, false);
}
public void dispatchReallyStop() {
moveToState(Fragment.ACTIVITY_CREATED, false);
}
public void dispatchDestroyView() {
moveToState(Fragment.CREATED, false);
}
public void dispatchDestroy() {
mDestroyed = true;
execPendingActions();
moveToState(Fragment.INITIALIZING, false);
mHost = null;
mContainer = null;
mParent = null;
}
FragmentManage的moveToState方法就負(fù)責(zé)了將自己管理的所有Fragment的狀態(tài)移動(dòng)到對(duì)應(yīng)的狀態(tài)上名段,當(dāng)mCurState變化阱扬,或者Fragment操作觸發(fā)都會(huì)調(diào)用該方法。
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragments that are not currently added will sit in the onCreate() state.
...
if (f.mState < newState) {
// For fragments that are created from a layout, when restoring from
// state we don't want to allow them to be created until they are
// being reloaded from the layout.
...
switch (f.mState) {
case Fragment.INITIALIZING:
...
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
...
}
case Fragment.ACTIVITY_CREATED:
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.performStart();
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
f.performResume();
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
f.performPause();
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
f.performStop();
}
case Fragment.STOPPED:
if (newState < Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
f.performReallyStop();
}
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
...
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
...
}
}
}
...
}
fragment的state取值伸辟,為前面提到的七中狀態(tài)麻惶,其中最低值是INITIALIZING狀態(tài),代表fragment剛創(chuàng)建信夫,還未被add窃蹋, 最高狀態(tài)值是RESUMED,代表fragment處于前臺(tái)静稻。 所以moveToState內(nèi)部分兩條線(xiàn)警没,狀態(tài)躍升,和狀態(tài)降低姊扔,里面各有一個(gè)switch判斷惠奸,注意到switch里每個(gè)case都沒(méi)有break梅誓,這意味著恰梢,狀態(tài)可以持續(xù)變遷,比如從INITIALIZING梗掰,一直躍升到RESUMED嵌言,將每個(gè)case都走一遍,每次case語(yǔ)句內(nèi)及穗,都會(huì)改變state的值摧茴。
Fragment狀態(tài)保存、恢復(fù)
主要實(shí)現(xiàn)代碼是FragmentManageImpl的saveAllState()和restoreAllState()方法埂陆。
FragmentActivity的onSaveInstance()方法中會(huì)間接調(diào)用FragmentManageImpl的saveAllState()方法苛白,而onCreate(Bundle)中會(huì)間接調(diào)用restoreAllState()娃豹。在Fragment的onCreate(Bundle)等初始化生命方法中會(huì)傳入保存狀態(tài)的Bundle,以供開(kāi)發(fā)者恢復(fù)存儲(chǔ)的數(shù)據(jù)购裙。而Fragment中view的狀態(tài)的恢復(fù)則是在回調(diào)了onCreateView()后得到開(kāi)發(fā)者返回的view懂版,手動(dòng)觸發(fā)view狀態(tài)的恢復(fù):
// FragmentManageImpl.class
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
...
if(f.mState < newState) { // 狀態(tài)升
...
switch(f.mState) {
...
case Fragment.CREATED:
...
f.mView = f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
...
f.performActivityCreated(f.mSavedFragmentState);
...
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
...
}
...
}
// Fragment.class
final void restoreViewState(Bundle savedInstanceState) {
if (mSavedViewState != null) {
mInnerView.restoreHierarchyState(mSavedViewState);
mSavedViewState = null;
}
mCalled = false;
onViewStateRestored(savedInstanceState);
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onViewStateRestored()");
}
}
Fragment常見(jiàn)錯(cuò)誤:
可以參考:http://www.reibang.com/p/d9143a92ad94
getActivity空指針錯(cuò)誤
狀態(tài)沒(méi)保存、值丟失
Can not perform this action after onSaveInstanceState異常
Fragment類(lèi)必須提供無(wú)參構(gòu)造方法
Fragment重疊顯示異常
其他
Fragment中還有回退棧躏率、動(dòng)畫(huà)躯畴、Android5.0中的共享元素及Activity動(dòng)畫(huà)、Fragment.retainInstance屬性薇芝、LoaderManager蓬抄、ChildFragmentManage等知識(shí)點(diǎn)這里先不討論了。