緣起
一直以來(lái)荒揣,筆者對(duì)fragment相關(guān)的這一堆API,內(nèi)部具體干了哪些事情不是很清楚焊刹,所以經(jīng)常會(huì)用起來(lái)心里有點(diǎn)小疙瘩系任,不是那么踏實(shí)“槌危總想著花些時(shí)間去源碼中看看赋除,大概從2、3年前也偶爾會(huì)點(diǎn)進(jìn)去看看非凌,那時(shí)看的有點(diǎn)云里霧里的举农,不是特別明白,最近又點(diǎn)進(jìn)去看了看敞嗡,加上可以單步代碼颁糟,算是對(duì)其理解有所小成航背,于是乎趁著記憶還是新鮮的,特此記錄下棱貌。
涉及到的類(lèi)
和fragment相關(guān)的類(lèi)有以下幾個(gè):
什么是Fragment
Fragment
是Android3.0引入的API玖媚,號(hào)稱(chēng)是為了解決屏幕碎片化和幫助重用代碼的構(gòu)造。中文翻譯為碎片婚脱、片段
今魔,或者理解成子Act
,相比Activity更輕量級(jí)障贸、更靈活错森,使用姿勢(shì)一般有以下2種:
-
靜態(tài)寫(xiě)在xml中,就和我們使用一般的widget一樣篮洁,如下:
寫(xiě)在act的xml布局文件中 在代碼里動(dòng)態(tài)生成涩维,添加、刪除等等袁波,代碼如下:
什么是FragmentTransaction
它封裝了一系列對(duì)fragment的操作,并一次性執(zhí)行這些操作篷牌∷看眼它的API就能明白,全是各種add/remove/replace/show/hide等等操作娃磺。
什么是FragmentManager
它是和某個(gè)act相關(guān)聯(lián)的薄湿,并不是全局唯一的,而是每個(gè)act都有一個(gè)自己的FragmentManager
偷卧,內(nèi)部有自己的狀態(tài)mCurState豺瘤,對(duì)應(yīng)外部act的生命周期狀態(tài)。它提供和act中fragment交互的API听诸。
示例代碼
private void addTestFragment() {
FragmentManager fm = getFragmentManager();
Fragment fragment = TestFragment.newInstance();
FragmentTransaction ft = fm.beginTransaction();
// ft.add(R.id.pf_base_fragment_container, fragment, "test_fragment");
ft.replace(R.id.pf_base_fragment_container, fragment);
ft.addToBackStack(null);
ft.commit();
}
之后的源碼解析都按照這段示例代碼來(lái)講坐求,源碼基于Android6.0。
在開(kāi)始分析之前晌梨,還得交代幾個(gè)事情桥嗤,如果我們仔細(xì)看了官方API會(huì)發(fā)現(xiàn)這里的FragmentManager
、FragmentTransaction
都是abstract的仔蝌,其真正的實(shí)現(xiàn)API對(duì)外當(dāng)然是沒(méi)有暴露泛领,不過(guò)我們看代碼知道分別是,如下圖:
具體分析
通過(guò)FragmentTransaction
這樣的API敛惊,我們可以一次執(zhí)行多個(gè)操作渊鞋,就像這樣:
ft.remove(R.id.fragment_container, fragment1);
ft.add(R.id.fragment_container, fragment2);
ft.hide(fragment3);
...等等還可以寫(xiě)很長(zhǎng)
它是怎么做到的呢?關(guān)鍵是其內(nèi)部的雙向鏈表結(jié)構(gòu):
接下來(lái)我們看下在此結(jié)構(gòu)上,F(xiàn)ragmentTransaction的一堆操作方法的實(shí)現(xiàn)锡宋,代碼如下:
void addOp(Op op) {
// 典型的雙向鏈表插入操作
if (mHead == null) {
mHead = mTail = op;
} else {
op.prev = mTail;
mTail.next = op;
mTail = op;
}
// 記錄這些動(dòng)畫(huà)信息
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
mNumOp++;
}
public FragmentTransaction add(Fragment fragment, String tag) {
doAddOp(0, fragment, tag, OP_ADD);
return this;
}
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
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對(duì)象上
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對(duì)象上
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
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;
}
public FragmentTransaction remove(Fragment fragment) {
Op op = new Op();
op.cmd = OP_REMOVE;
op.fragment = fragment;
addOp(op);
return this;
}
public FragmentTransaction hide(Fragment fragment) {
Op op = new Op();
op.cmd = OP_HIDE;
op.fragment = fragment;
addOp(op);
return this;
}
public FragmentTransaction show(Fragment fragment) {
Op op = new Op();
op.cmd = OP_SHOW;
op.fragment = fragment;
addOp(op);
return this;
}
public FragmentTransaction detach(Fragment fragment) {
Op op = new Op();
op.cmd = OP_DETACH;
op.fragment = fragment;
addOp(op);
return this;
}
public FragmentTransaction attach(Fragment fragment) {
Op op = new Op();
op.cmd = OP_ATTACH;
op.fragment = fragment;
addOp(op);
return this;
}
public FragmentTransaction setCustomAnimations(int enter, int exit) {
return setCustomAnimations(enter, exit, 0, 0);
}
public FragmentTransaction setCustomAnimations(int enter, int exit,
int popEnter, int popExit) {
mEnterAnim = enter;
mExitAnim = exit;
mPopEnterAnim = popEnter;
mPopExitAnim = popExit;
return this;
}
public FragmentTransaction setTransition(int transition) {
mTransition = transition;
return this;
}
@Override
public FragmentTransaction addSharedElement(View sharedElement, String name) {
String transitionName = sharedElement.getTransitionName();
if (transitionName == null) {
throw new IllegalArgumentException("Unique transitionNames are required for all" +
" sharedElements");
}
if (mSharedElementSourceNames == null) {
mSharedElementSourceNames = new ArrayList<String>();
mSharedElementTargetNames = new ArrayList<String>();
}
mSharedElementSourceNames.add(transitionName);
mSharedElementTargetNames.add(name);
return this;
}
public FragmentTransaction setTransitionStyle(int styleRes) {
mTransitionStyle = styleRes;
return this;
}
public FragmentTransaction addToBackStack(String name) {
if (!mAllowAddToBackStack) {
throw new IllegalStateException(
"This FragmentTransaction is not allowed to be added to the back stack.");
}
mAddToBackStack = true;
mName = name;
return this;
}
從源碼我們可以看出儡湾,各種不同操作方法內(nèi)部實(shí)際上只是個(gè)不同cmd的Op對(duì)象,通過(guò)雙向鏈表鏈起來(lái)了而已执俩,至于為什么要是雙向的呢徐钠,單鏈表不行嗎?那是因?yàn)镕ragment在act層面維護(hù)了一個(gè)回退棧役首,即如果你調(diào)用了ft.addToBackStack(null);
這樣的代碼尝丐,那么當(dāng)你按下back鍵的時(shí)候不是直接結(jié)束當(dāng)前act,而是先從fragment棧里嘗試pop出來(lái)?xiàng)m數(shù)膄ragment宋税。它不僅要向前進(jìn)摊崭,還得支持向后退。
緊接著的是commit的源碼杰赛,如下:
public int commit() {
return commitInternal(false);
}
public int commitAllowingStateLoss() {
return commitInternal(true);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) {
throw new IllegalStateException("commit already called");
}
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
PrintWriter pw = new FastPrintWriter(logw, false, 1024);
dump(" ", null, pw, null);
pw.flush();
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
// FragmentManagerImpl#enqueueAction方法
/**
* Adds an action to the queue of pending actions.
*
* @param action the action to add
* @param allowStateLoss whether to allow loss of state information
* @throws IllegalStateException if the activity has been destroyed
*/
public void enqueueAction(Runnable action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
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);
}
}
}
我們看到commit
方法并沒(méi)有立即執(zhí)行這個(gè)動(dòng)作,只是入隊(duì)了action(通過(guò)mPendingActions.add(action);)矮台,系統(tǒng)會(huì)在下次event loop到來(lái)時(shí)執(zhí)行它乏屯。
FragmentManagerImpl的其他關(guān)鍵方法
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
/**
* Only call from main thread!
*/
public boolean execPendingActions() {
if (mExecutingActions) {
throw new IllegalStateException("Recursive entry to executePendingTransactions");
}
if (Looper.myLooper() != mHost.getHandler().getLooper()) {
throw new IllegalStateException("Must be called from main thread of process");
}
boolean didSomething = false;
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);
}
mExecutingActions = true;
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
}
if (mHavePendingDeferredStart) {
boolean loadersRunning = false;
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null && f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
if (!loadersRunning) {
mHavePendingDeferredStart = false;
startPendingDeferredFragments();
}
}
return didSomething;
}
具體要執(zhí)行的action就是BackStackRecord#run
方法,因?yàn)槲覀冏⒁獾剿约簩?shí)現(xiàn)了Runnable
接口瘦赫,來(lái)看下其實(shí)現(xiàn):
public void run() {
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Run: " + this);
}
if (mAddToBackStack) {
if (mIndex < 0) {
throw new IllegalStateException("addToBackStack() called after commit()");
}
}
bumpBackStackNesting(1);
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
calculateFragments(firstOutFragments, lastInFragments);
beginTransition(firstOutFragments, lastInFragments, false);
Op op = mHead;
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
break;
case OP_REPLACE: {
Fragment f = op.fragment;
int containerId = f.mContainerId;
if (mManager.mAdded != null) {
for (int i = 0; i < mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG,
"OP_REPLACE: adding=" + f + " old=" + old);
}
// 注意這個(gè)判斷辰晕,必須是同一個(gè)containerId里面的,換句話說(shuō)你如果是在2個(gè)不同的container里面做fragment的replace操作确虱,互相是不會(huì)影響的
if (old.mContainerId == containerId) {
if (old == f) {
op.fragment = f = null;
} else {
if (op.removed == null) {
op.removed = new ArrayList<Fragment>();
}
op.removed.add(old);
old.mNextAnim = op.exitAnim;
if (mAddToBackStack) {
old.mBackStackNesting += 1;
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Bump nesting of "
+ old + " to " + old.mBackStackNesting);
}
}
mManager.removeFragment(old, mTransition, mTransitionStyle);
}
}
}
}
// 注意這個(gè)非空判斷含友,因?yàn)閞eplace自己的時(shí)候f會(huì)被置為null,相當(dāng)于什么也不會(huì)做的
if (f != null) {
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
}
break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.removeFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.hideFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.showFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.detachFragment(f, mTransition, mTransitionStyle);
}
break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.attachFragment(f, mTransition, mTransitionStyle);
}
break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.next;
}
// 不帶fragment參數(shù)的狀態(tài)轉(zhuǎn)移
mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}
這個(gè)方法主要做的事情是向前遍歷Op雙向鏈表校辩,根據(jù)cmd的不同調(diào)用FragmentManagerImpl的以下方法窘问,特別注意下這里的OP_REPLACE
cmd,看代碼我們知道它其實(shí)相當(dāng)于add/remove的組合宜咒,即如果有added會(huì)把所以已經(jīng)added了的先remove掉惠赫,再將新的add進(jìn)去,效果上是這樣故黑。
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
if (DEBUG) Log.v(TAG, "add: " + 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 (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
if (moveToStateNow) {
moveToState(fragment);
}
}
}
public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
// 加到回退棧中和不加的區(qū)別
final boolean inactive = !fragment.isInBackStack();
if (!fragment.mDetached || inactive) {
if (false) {
// Would be nice to catch a bad remove here, but we need
// time to test this to make sure we aren't crashes cases
// where it is not a problem.
if (!mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment not added: " + fragment);
}
}
if (mAdded != null) {
mAdded.remove(fragment);
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false;
fragment.mRemoving = true;
// 沒(méi)有加到回退棧中則狀態(tài)退的更徹底儿咱,到狀態(tài)0而不是狀態(tài)1,區(qū)別就是最后的幾個(gè)destory相關(guān)的callback會(huì)不會(huì)被調(diào)用场晶。
moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
transition, transitionStyle, false);
}
}
public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "hide: " + fragment);
if (!fragment.mHidden) {
fragment.mHidden = true;
if (fragment.mView != null) {
Animator anim = loadAnimator(fragment, transition, false,
transitionStyle);
if (anim != null) {
anim.setTarget(fragment.mView);
// Delay the actual hide operation until the animation finishes, otherwise
// the fragment will just immediately disappear
final Fragment finalFragment = fragment;
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (finalFragment.mView != null) {
finalFragment.mView.setVisibility(View.GONE);
}
}
});
setHWLayerAnimListenerIfAlpha(finalFragment.mView, anim);
anim.start();
} else {
fragment.mView.setVisibility(View.GONE);
}
}
if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.onHiddenChanged(true);
}
}
public void showFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "show: " + fragment);
if (fragment.mHidden) {
fragment.mHidden = false;
if (fragment.mView != null) {
Animator anim = loadAnimator(fragment, transition, true,
transitionStyle);
if (anim != null) {
anim.setTarget(fragment.mView);
setHWLayerAnimListenerIfAlpha(fragment.mView, anim);
anim.start();
}
fragment.mView.setVisibility(View.VISIBLE);
}
if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.onHiddenChanged(false);
}
}
public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "detach: " + fragment);
if (!fragment.mDetached) {
fragment.mDetached = true;
if (fragment.mAdded) {
// We are not already in back stack, so need to remove the fragment.
if (mAdded != null) {
if (DEBUG) Log.v(TAG, "remove from detach: " + fragment);
mAdded.remove(fragment);
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false;
moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
}
}
}
public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "attach: " + fragment);
if (fragment.mDetached) {
fragment.mDetached = false;
if (!fragment.mAdded) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
if (DEBUG) Log.v(TAG, "add from attach: " + fragment);
mAdded.add(fragment);
fragment.mAdded = true;
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
moveToState(fragment, mCurState, transition, transitionStyle, false);
}
}
}
上面的run方法在對(duì)這一系列Op處理完后混埠,調(diào)用了下面的方法:
mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true);
,對(duì)應(yīng)的源碼如下:
void moveToState(Fragment f) {
moveToState(f, mCurState, 0, 0, false);
}
void moveToState(int newState, boolean always) {
moveToState(newState, 0, 0, always);
}
// 這里調(diào)用的是這個(gè)方法
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) {
boolean loadersRunning = false;
for (int i=0; i<mActive.size(); i++) {
Fragment f = mActive.get(i);
if (f != null) {
// fragment狀態(tài)改變的方法诗轻,其各種生命周期回調(diào)也在這里調(diào)用钳宪,是最重要的一個(gè)方法!!使套!
moveToState(f, newState, transit, transitStyle, false);
if (f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
}
if (!loadersRunning) {
startPendingDeferredFragments();
}
if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
mHost.onInvalidateOptionsMenu();
mNeedMenuInvalidate = false;
}
}
}
這里我們需要對(duì)mManager.mCurState
這個(gè)值的變化細(xì)說(shuō)下罐呼,其初始值是這樣的:
int mCurState = Fragment.INITIALIZING;
Fragment的所有可能狀態(tài):
static final int INVALID_STATE = -1; // Invalid state used as a null value.
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.
FragmentManager中有一堆public void dispatchxxx
這樣的方法,如下:
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() {
moveToState(Fragment.STOPPED, false);
}
public void dispatchDestroyView() {
moveToState(Fragment.CREATED, false);
}
public void dispatchDestroy() {
mDestroyed = true;
execPendingActions();
moveToState(Fragment.INITIALIZING, false);
mHost = null;
mContainer = null;
mParent = null;
}
而這些正好是和act的生命周期對(duì)應(yīng)起來(lái)侦高,也就是說(shuō)這些方法是隨著act進(jìn)入到不同的生命周期而被調(diào)用的嫉柴,即mCurState
的值是被這些方法觸發(fā)設(shè)置的。比如act進(jìn)入到了Resume狀態(tài)奉呛,那么FragmentManagerImpl.mCurState也就等于Fragment.RESUMED计螺。
最后,我們分析下fragment狀態(tài)轉(zhuǎn)移最重要的一個(gè)方法瞧壮,如下:
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
if (DEBUG && false) Log.v(TAG, "moveToState: " + f
+ " oldState=" + f.mState + " newState=" + newState
+ " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));
// Fragments that are not currently added will sit in the onCreate() state.
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
if (f.mRemoving && newState > f.mState) {
// While removing a fragment, we can't change it to a higher state.
newState = f.mState;
}
// Defer start if requested; don't allow it to move to STARTED or higher
// if it's not already started.
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
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.
if (f.mFromLayout && !f.mInLayout) {
return;
}
if (f.mAnimatingAway != null) {
// The fragment is currently being animated... but! Now we
// want to move our state back up. Give up on waiting for the
// animation, move to whatever the final state should be once
// the animation is done, and then we can proceed from there.
f.mAnimatingAway = null;
moveToState(f, f.mStateAfterAnimating, 0, 0, true);
}
switch (f.mState) {
case Fragment.INITIALIZING:
if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
if (f.mSavedFragmentState != null) {
f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
f.mTarget = getFragment(f.mSavedFragmentState,
FragmentManagerImpl.TARGET_STATE_TAG);
if (f.mTarget != null) {
f.mTargetRequestCode = f.mSavedFragmentState.getInt(
FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
}
f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
if (!f.mUserVisibleHint) {
f.mDeferStart = true;
if (newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
}
}
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
f.mCalled = false;
f.onAttach(mHost.getContext());
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
mHost.onAttachFragment(f);
}
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
}
f.mRetaining = false;
if (f.mFromLayout) {
// For fragments that are part of the content view
// layout, we need to instantiate the view immediately
// and the inflater will take care of adding it.
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
throwException(new IllegalArgumentException(
"No view found for id 0x"
+ Integer.toHexString(f.mContainerId) + " ("
+ f.getResources().getResourceName(f.mContainerId)
+ ") for fragment " + f));
}
}
f.mContainer = container;
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
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);
}
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
f.performActivityCreated(f.mSavedFragmentState);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
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.mResumed = true;
f.performResume();
// Get rid of this in case we saved it and never needed it.
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();
f.mResumed = false;
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
f.performStop();
}
case Fragment.STOPPED:
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
if (f.mView != null) {
// Need to save the current view state if not
// done already.
if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
saveFragmentViewState(f);
}
}
f.performDestroyView();
if (f.mView != null && f.mContainer != null) {
Animator anim = null;
if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
anim = loadAnimator(f, transit, false,
transitionStyle);
}
if (anim != null) {
final ViewGroup container = f.mContainer;
final View view = f.mView;
final Fragment fragment = f;
container.startViewTransition(view);
f.mAnimatingAway = anim;
f.mStateAfterAnimating = newState;
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator anim) {
container.endViewTransition(view);
if (fragment.mAnimatingAway != null) {
fragment.mAnimatingAway = null;
moveToState(fragment, fragment.mStateAfterAnimating,
0, 0, false);
}
}
});
anim.setTarget(f.mView);
setHWLayerAnimListenerIfAlpha(f.mView, anim);
anim.start();
}
f.mContainer.removeView(f.mView);
}
f.mContainer = null;
f.mView = null;
}
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
if (mDestroyed) {
if (f.mAnimatingAway != null) {
// The fragment's containing activity is
// being destroyed, but this fragment is
// currently animating away. Stop the
// animation right now -- it is not needed,
// and we can't wait any more on destroying
// the fragment.
Animator anim = f.mAnimatingAway;
f.mAnimatingAway = null;
anim.cancel();
}
}
if (f.mAnimatingAway != null) {
// We are waiting for the fragment's view to finish
// animating away. Just make a note of the state
// the fragment now should move to once the animation
// is done.
f.mStateAfterAnimating = newState;
newState = Fragment.CREATED;
} else {
if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
if (!f.mRetaining) {
f.performDestroy();
}
f.mCalled = false;
f.onDetach();
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onDetach()");
}
if (!keepActive) {
if (!f.mRetaining) {
makeInactive(f);
} else {
f.mHost = null;
f.mParentFragment = null;
f.mFragmentManager = null;
f.mChildFragmentManager = null;
}
}
}
}
}
}
f.mState = newState;
}
這個(gè)方法最終會(huì)將FragmentManager的狀態(tài)賦值給fragment登馒,另外這個(gè)方法會(huì)根據(jù)不同的state調(diào)用各種onAttach, Fragment.performXXX
,進(jìn)而調(diào)到用戶(hù)自己override的fragment的各種生命周期方法咆槽,比如onCreate陈轿、onCreateView等等。
總結(jié)
show/hideFragment只是改變fragment根View的visibility秦忿,最多帶上個(gè)動(dòng)畫(huà)效果麦射,另外只有本身是hidden的fragment,調(diào)用show才起作用灯谣,否則沒(méi)用的潜秋,fragment.onHiddenChanged會(huì)被觸發(fā);其次不會(huì)有生命周期callback觸發(fā)胎许,當(dāng)然了這些操作的前提是已經(jīng)被add了的fragment峻呛;
addFragment的時(shí)候,不管加不加入回退棧都一樣辜窑,經(jīng)歷的生命周期如下:onAttach钩述、onCreate、onCreateView谬擦、onActivityCreate切距、onStart、onResume惨远;
-
removeFragment的時(shí)候谜悟,經(jīng)歷的生命周期如下:onPause、onStop北秽、onDestroyView葡幸,如果不加回退棧還會(huì)繼續(xù)走
onDestroy、onDetach贺氓;remove的時(shí)候不僅從mAdded中移除fragment蔚叨,也從mActive中移除了;
FragmentManagerImpl中關(guān)鍵字段申明 attach/detachFragment的前提都是已經(jīng)add了的fragment,其生命周期回調(diào)不受回退棧影響蔑水。attach的時(shí)候onCreateView邢锯、onActivityCreate、onStart搀别、onResume會(huì)被調(diào)用丹擎;detach的時(shí)候onPause、onStop歇父、onDestroyView會(huì)被調(diào)用蒂培,onDestroy、onDetach不會(huì)被調(diào)用榜苫;對(duì)應(yīng)的fragment只是從mAdded中移除了护戳;
remove、detachFragment的時(shí)候垂睬,當(dāng)
FragmentManagerImpl.makeInactive()
被調(diào)用的話媳荒,fragment就變成了一個(gè)空殼,里面絕大部分字段都會(huì)被置空驹饺,注意只是系統(tǒng)內(nèi)部自己管理的字段肺樟,假如你在自己的fragment子類(lèi)中引入了新的字段,當(dāng)你重用這些類(lèi)的對(duì)象時(shí)要自己處理這種情況(即系統(tǒng)不會(huì)reset你自己造的字段)逻淌,代碼如下:
void makeInactive(Fragment f) {
if (f.mIndex < 0) {
return;
}
if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
mActive.set(f.mIndex, null);
if (mAvailIndices == null) {
mAvailIndices = new ArrayList<Integer>();
}
mAvailIndices.add(f.mIndex);
mHost.inactivateFragment(f.mWho);
f.initState();
}
// Fragment.initState方法
/**
* Called by the fragment manager once this fragment has been removed,
* so that we don't have any left-over state if the application decides
* to re-use the instance. This only clears state that the framework
* internally manages, not things the application sets.
*/
void initState() {
mIndex = -1;
mWho = null;
mAdded = false;
mRemoving = false;
mResumed = false;
mFromLayout = false;
mInLayout = false;
mRestored = false;
mBackStackNesting = 0;
mFragmentManager = null;
mChildFragmentManager = null;
mHost = null;
mFragmentId = 0;
mContainerId = 0;
mTag = null;
mHidden = false;
mDetached = false;
mRetaining = false;
mLoaderManager = null;
mLoadersStarted = false;
mCheckedForLoaderManager = false;
}