Fragment 的生成方式有兩種,一種是寫在layout文件裏的, 如:java
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/titles" android:layout_width="match_parent" android:layout_height="match_parent" android:name="play.apilearn.HistoryActivity$TitlesFragment" /> </FrameLayout>
另外一種是在運行時動態加載:android
FragmentManager fm = getFragmentManager(); FragmentManager.enableDebugLogging(true); int count = fm.getBackStackEntryCount(); Log.d(LOG_TAG," backstack size:" + count); //fm.getBackStackEntryAt(0).getName(); FragmentTransaction ft = fm.beginTransaction(); ft.replace(R.id.fullscreen_content, BlankFragment.newInstance(null, null)); ft.addToBackStack(null); ft.commit();
先看第二種是如何實現的。api
首先明確幾個關鍵的類,FragmentManager的繼承類(實現類)是FragmentManagerImp, FragmentTransaction的實現類是BackStackRecord。安全
在FragmentManagerImp中 beginTransaction方法返回了BackStackRecord實例:ide
@Override public FragmentTransaction beginTransaction() { return new BackStackRecord(this); }
接下來咱們來看看這個 事務 作了什麼:oop
FragmentTransaction ft = fm.beginTransaction(); ft.replace(R.id.fullscreen_content, BlankFragment.newInstance(null, null)); ft.addToBackStack(null); ft.commit();
BackStackRecord不單繼承了 FragmentTransaction ,同時實現了BackStackEntry 和Runnable 接口;post
實現BackStackEntry 是爲了讓Fragmentmanager管理, 實現Runnable 是爲了把BackStackRecord對象做爲消息post到UI線程的消息隊列中。backStackRecord是一個事務,該事務中能夠執行一個或多個操做(add、remove等), 這些操做的實際執行都是在UI主線程中進行的。這些操做保存在一個雙向鏈表中, 鏈表的頭和尾分別是 mHead 和 mTailthis
final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, Runnable { final FragmentManagerImpl mManager; // operation types 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; static final class Op { Op next; Op prev; int cmd; //該操做的目標fragment Fragment fragment; int enterAnim; int exitAnim; int popEnterAnim; int popExitAnim; //對於 OP_REPLACE 操做,removed表示該操做中移除的fragment,它們和目標fragment共享一個containerId ArrayList<Fragment> removed; } ... Op mHead; Op mTail; ... boolean mAddToBackStack; boolean mAllowAddToBackStack = true; String mName; boolean mCommitted; int mIndex = -1;
下面看這行代碼作了什麼:spa
ft.replace(R.id.fullscreen_content, BlankFragment.newInstance(null, null));
定位到BackStackRecord的 replace 方法:線程
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; }
而後定位到 doAddOp 方法,注意操做類型 opcmd 的值是 OP_REPLACE,該值被記錄在Op對象中:
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); }
addOp又作了什麼呢? 注意BackStackRecord是一個事務,能夠包含有序的多個操做,addOp就是把當前操做保存在操做鏈的尾部:
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++; }
接下來看addToBackStack( String name ):
ft.addToBackStack(null); // BackStackRecord.java 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; }
能夠看到該方法只是 把 mAddToBackStack 標識置位true, 該標識在 FragmentManager執行BackStackRecord中記錄的操做時會用到。
最後是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(TAG); PrintWriter pw = new PrintWriter(logw); dump(" ", null, pw, null); } mCommitted = true; if (mAddToBackStack) { mIndex = mManager.allocBackStackIndex(this); } else { mIndex = -1; } mManager.enqueueAction(this, allowStateLoss); return mIndex; }
commit 調用了內部方法 commitInternal(..) , 在 commitInternal方法返回以前,調用了FragmentManagerImp的enqueAction, 這個action對象就是當前的BackStackRecord對象(用this表示),它是一個事務, 前面說過, BackStackRecord實現了 Runnable 接口,做爲一個action添加到FragmentManager的 pendingActions隊列中。 fragmentManager會向UI主線程消息隊列裏post一個執行消息(mExecCommit)。當消息被主線程取出執行(comsume)的時候,會執行pendingActions隊列裏的每個action的run方法,因此接下來應該看 BackStackRecord 的run()方法裏到底作了什麼,不難猜想,固然是以前記錄在 Op中的一系列(也多是一個)操做。
//FragmentManager.java Runnable mExecCommit = new Runnable() { @Override public void run() { execPendingActions(); } }; .... /** * 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 || mActivity == null) { throw new IllegalStateException("Activity has been destroyed"); } if (mPendingActions == null) { mPendingActions = new ArrayList<Runnable>(); } mPendingActions.add(action); if (mPendingActions.size() == 1) { mActivity.mHandler.removeCallbacks(mExecCommit); mActivity.mHandler.post(mExecCommit); } } } ... /** * Only call from main thread! */ public boolean execPendingActions() { if (mExecutingActions) { throw new IllegalStateException("Recursive entry to executePendingTransactions"); } if (Looper.myLooper() != mActivity.mHandler.getLooper()) { throw new IllegalStateException("Must be called from main thread of process"); } ... 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(); mActivity.mHandler.removeCallbacks(mExecCommit); } mExecutingActions = true; for (int i=0; i<numActions; i++) { mTmpActions[i].run(); // 執行BackStackRecord 對象的run 方法 mTmpActions[i] = null; } mExecutingActions = false; didSomething = true; } ... }
另外這裏用到了 mAddToBackStack標識, 若爲TRUE, fragmentManager會給當前事務分配一個 index, 注意是在commit ()分配的, 若是你在commit後又調用了 addToBackStack(String name ) 方法,那麼mAddToBackStack 標識會被置位true, 可是卻沒有分配到index (默認 -1) 。當消息被執行時 (在事務的run方法中), mIndex 和 mAddToBackStack 同時被檢查,若是 mAddToBackStack 爲true 而 mIndex 小於 0,
事務會拋出 IllegalStateException 。這是實現事務的一種安全檢查。
從 run() 方法中能夠看出這一邏輯:
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); 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; 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); if (f == null || old.mContainerId == f.mContainerId) { 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); } } } } 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; } mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); if (mAddToBackStack) { mManager.addBackStackState(this); } }
最後檢查了 mAddToBackStack 標識,mBackStack 是在activity 收到 返回事件時去檢查的。
void addBackStackState(BackStackRecord state) { if (mBackStack == null) { mBackStack = new ArrayList<BackStackRecord>(); } mBackStack.add(state); reportBackStackChanged(); }
Ps: 解釋下 bumpBackStackNesting(int amt), 這個方法的意思是,若是當前事務要放入activity的回退棧,就在當前事務涉及的fragment的mBackStackNesting字段中記錄當前事務處於回退棧的第幾項(棧頂是 1),字段mBackStackNesting能夠用來判斷fragment是否在回退棧中。
//BackStackRecord.java void bumpBackStackNesting(int amt) { if (!mAddToBackStack) { return; } if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting in " + this + " by " + amt); Op op = mHead; while (op != null) { if (op.fragment != null) { op.fragment.mBackStackNesting += amt; if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " + op.fragment + " to " + op.fragment.mBackStackNesting); } if (op.removed != null) { for (int i=op.removed.size()-1; i>=0; i--) { Fragment r = op.removed.get(i); r.mBackStackNesting += amt; if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " + r + " to " + r.mBackStackNesting); } } op = op.next; } } //Fragment.java final boolean isInBackStack() { return mBackStackNesting > 0; }
回到 run方法, 能夠看到根據相應的操做命令(ADD,REMOVE, REPLACE, HIDE, ATTACH等)調用FragmentManager的相應方法。 並在最後根據當前事務的 mAddToBackStack標識決定是否把當前事務加入FragmentManager的 mBackStack<BackStackRecord> 隊列。