Fragment的管理中使用了事务的概念,类似于数据库中的事务,可以把对Fragment操作打包成事务提交,(API for performing a set of Fragment operations)
,通过FragmentTransaction的addToBackStack和FragmentManager的popBackStack可以进行事务入栈和回滚操作
1.FragmentTransaction对象
我们一般通过FragmentManager的beginTransaction()获取FragmentTransaction对象,但FragmentTransaction是一个抽象类,我们实际拿到的是一个什么样的对象,getFragmentManager()获取的是FragmentManagerImpl对象
FragmentManagerImpl的方法实现
public FragmentTransaction beginTransaction() { return new BackStackRecord(this); }
我们调用beginTransaction,实际是拿到了一个BackStackRecord对象
看一下BackStackRecord的继承结构
Entry of an operation on the fragment back stack. final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, Runnable
BackStackRecord继承自FragmentTransaction,此外还实现了两个接口:FragmentManager.BackAtackEntry,Runnable
1.FragmentManager.BackAtackEntry是对Fragment事务栈管理的对象的抽象,在HashMap中有类似的Entry概念。
我们每次获取FragmentTransaction 对象并commit都是进行一次Fragment事务的提交,事务由FragmentManager管理
* Representation of an entry on the fragment back stack, as created * with {@link FragmentTransaction#addToBackStack(String) * FragmentTransaction.addToBackStack()}. Entries can later be * retrieved with {@link FragmentManager#getBackStackEntryAt(int) * FragmentManager.getBackStackEntryAt()}. * * <p>Note that you should never hold on to a BackStackEntry object; * the identifier as returned by {@link #getId} is the only thing that * will be persisted across activity instances.
2.Runnable接口
实现了Runnable接口说明BackStackRecord是一个可执行对象,这也是Fragment原理中比较关键的一点,正式使用Handler对Fragment事务进行了调度执行。
看一下FragmentTransaction的commit方法
public int commit() { return commitInternal(false); }
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; }FragmentManager把事务入队mPendingActions,并通过主线程调度mExecCommit,执行execPendingActions方法,该方法调用了BackStackRecord的run方法
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); } } }Runnable mExecCommit = new Runnable() { @Override public void run() { execPendingActions(); } };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; } ``````` return didSomething; }现在看一下BackStackRecord的run方法干了什么
run方法遍历了一个操作命令链表,对每一个命令分别调用对应的FragmentManager方法执行对应的操作(以及transitions相关的操作和事务入栈操作)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); } 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); } } } } 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); } }这个命令链表是如何得到的呢?BackStackRecord还继承了FragmentTransaction,这了由对Fragment的各种操作add/replace/show/hide/remove
3.FragmentTransaction抽象类,以add实现为例:操作方法实现会调用doAddOp方法,创建一个Op对象添加到事务的操作链表里,Op是对Fragment操作进行的抽象主要有操作类型和目标Fragment
public FragmentTransaction add(int containerViewId, Fragment fragment) { doAddOp(containerViewId, fragment, null, 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.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;
addOp(op); }void addOp(Op op) {
} Op op = new Op(); op.cmd = opcmd; op.fragment = fragment;总结:FragmentTransaction是Fragment事务操作的体现,FragmentTransaction本身的操作方法只是对事务操作命令的保存,} else { op.prev = mTail; mTail.next = op; mTail = op; } op.enterAnim = mEnterAnim; op.exitAnim = mExitAnim; op.popEnterAnim = mPopEnterAnim; op.popExitAnim = mPopExitAnim; mNumOp++; }具体的实现是在commit时,提交给主线程消息处理机制去执行具体的Fragment操作。
if (mHead == null) { mHead = mTail = op;