概述 在Fragment使用中,有时候需要对Fragment进行add
、remove
、show
、hide
、replace
等操作来进行Fragment的显示隐藏等管理,这些管理是通过FragmentTransaction
进行事务管理的。事务管理是对于一系列操作进行管理,一个事务包含一个或多个操作命令,是逻辑管理的工作单元。一个事务开始于第一次执行操作语句,结束于Commit。通俗地将,就是把多个操作缓存起来,等调用commit的时候,统一批处理。下面会对Fragmeng的事务管理做一个代码分析
分析入口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 protected void showFragment (@IdRes int containerViewId, Class<? extends Fragment> clz) { FragmentManager fm = getFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); Fragment f; if ((f = fm.findFragmentByTag(clz.getName())) == null ) { try { f = clz.newInstance(); ft.add(containerViewId, f, clz.getName()); } catch (Exception e) { e.printStackTrace(); } } else { ft.show(f); } ft.commit(); }
上面是一个简单的显示Fragment的栗子,简单判断一下Fragment是否已添加过,添加过就直接show,否则构造一个Fragment,最后提交事务。
代码分析 FragmentManager 上图是获取FragmentManager的大体过程
要管理Fragment事务,首先是需要拿到FragmentManager,在Activity中可以通过getFragmentManager()
方法获取(使用兼容包的话,通过FragmentActivity#getSupportFragmentManager()
),在这里我们就不对兼容包进行分析了
1 2 3 4 5 6 7 8 9 final FragmentController mFragments = FragmentController.createController(new HostCallbacks());public FragmentManager getFragmentManager () { return mFragments.getFragmentManager(); }
FragmentManager是一个抽象类,它是通过mFragments.getFragmentManager()来获取的,mFragments是FragmentController对象,它通过FragmentController.createController(new HostCallbacks())
生成,这是一个静态工厂方法:
1 2 3 public static final FragmentController createController (FragmentHostCallback<?> callbacks) { return new FragmentController(callbacks); }
在这里面直接new了一个FragmentController对象,注意FragmentController的构造方法需要传入一个FragmentHostCallback
FragmentController构造方法 1 2 3 4 private final FragmentHostCallback<?> mHost;private FragmentController (FragmentHostCallback<?> callbacks) { mHost = callbacks; }
构造方法很简单,传入了一个FragmentHostCallback实例
FragmentController#getFragmentManager 1 2 3 public FragmentManager getFragmentManager () { return mHost.getFragmentManagerImpl(); }
这里又调用了mHost的getFragmentManagerImpl方法,希望童鞋们没有被绕晕,mHost是一个FragmentHostCallback实例,那我们回过头来看看它传进来的地方
FragmentHostCallback 这个FragmentHostCallback是一个抽象类,我们可以看到,在Activity中是传入了 Activity#HostCallbacks
内部类,这个就是FragmentHostCallback的实现类
FragmentHostCallback#getFragmentManagerImpl 1 2 3 4 final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();FragmentManagerImpl getFragmentManagerImpl () { return mFragmentManager; }
终于找到FragmentManager的真身FragmentManagerImpl
了
FragmentManagerImpl#beginTransaction 1 2 3 4 @Override public FragmentTransaction beginTransaction () { return new BackStackRecord(this ); }
可以看到,所谓的FragmentTransaction其实就是一个BackStackRecord。到现在,FragmentManager和FragmentTransaction我们都找到了。下图就是各个类之间的关系:
下面开始真正的事务管理分析,我们先选择一个事务add来进行分析
FragmentTransaction#add 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 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("..." ); } fragment.mTag = tag; } if (containerViewId != 0 ) { if (containerViewId == View.NO_ID) { throw new IllegalArgumentException("..." ); } if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) { throw new IllegalStateException("" ); } fragment.mContainerId = fragment.mFragmentId = containerViewId; } Op op = new Op(); op.cmd = opcmd; op.fragment = fragment; addOp(op); } 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++; }
add的操作步骤为:
设置fragment的FragmentManagerImpl
设置fragment的tag
设置fragment的mContainerId以及mFragmentId
插入一个类型为OP_ADD的操作到链表最后
这里用到了一个类:
1 2 3 4 5 6 7 8 9 10 11 static final class Op { Op next; Op prev; int cmd; Fragment fragment; int enterAnim; int exitAnim; int popEnterAnim; int popExitAnim; ArrayList<Fragment> removed; }
这是一个操作链表节点。所有add、remove、hide等事物最终会形成一个操作链
FragmentTransaction#commit 等所有操作都插入后,最后我们需要调用FragmentTransaction的commit方法,操作才会真正地执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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; }
FragmentManagerImpl#enqueueAction 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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); } } }
这里把操作添加到mPendingActions
列表里去。并通过mHost.getHandler()获取Handler发送执行请求。从上面的分析知道,mHost就是Activity的HostCallbacks,构造方法中把Activity的mHandler传进去了,这里执行的mHost.getHandler()
获取到的也就是Activity中的mHandler,这样做是因为需要在主线程中执行
1 final Handler mHandler = new Handler();
再看看mExecCommit中做了什么操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 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 ; } doPendingDeferredStart(); return didSomething; }
插入了事物之后,就是在主线程中把需要处理的事务统一处理,处理事务是通过执行mTmpActions[i].run()
进行的,这个mTmpActions[i]就是前面我们通过enqueueAction方法插入的BackStackRecord,童鞋们可能没注意到,它可是一个Runnable,我们来看看它的定义
1 2 3 4 5 6 final class BackStackRecord extends FragmentTransaction implements FragmentManager .BackStackEntry , Runnable { static final String TAG = FragmentManagerImpl.TAG; ... ... }
兜兜转转,我们又回到了BackStackRecord
BackStackRecord#run 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 public void run () { ...... if (mManager.mCurState >= Fragment.CREATED) { 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 = mManager.mAdded.size() - 1 ; i >= 0 ; i--) { Fragment old = mManager.mAdded.get(i); 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 ; } 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 ); } }
到这一步,提交的事务就被真正执行了,我们知道,即使commit了事务之后,也不是同步执行的,是通过Handler发送到主线程执行的。
所有事务的处理都是在run方法里面执行,但是我们留意到,想要搞清楚add、remove等事务背后真正做了什么,还需要深入了解FragmentManagerImpl。
本文主要讲解Fragment事务的流程,FragmentManagerImpl的分析准备放到下一篇分析文章Fragment源码分析 中,相信通过分析之后,就可以对Fragment的生命周期也有一个很好的认识了