源码分析Fragmentd的BackStack管理过程

原文出处:http://blog.csdn.net/bigconvience/article/details/30502071

1. Fragment基本用法

为了管理Activity中的fragments,需要调用Activity中的getFragmentManager()方法。因为FragmentManager的API是在Android 3.0,也即API level 11开始引入的,所以对于之前的版本,需要使用support library v4中的FragmentActivity,并且使用getSupportFragmentManager()方法。
用FragmentManager可以做的工作有:
得到Activity中存在的fragment:
  使用findFragmentById()或findFragmentByTag()方法。
  将fragment弹出back stack:
popBackStack():
    将back stack中最后一次的fragment转换弹出。如果没有可以出栈的东西,返回false。
 这个函数是异步的:它将弹出栈的请求加入队列,但是这个动作直到应用回到事件循环才会执行。
为back stack加上监听器:
  addOnBackStackChangedListener()
使用Fragment时,可以执行一些动作,比如增加、移除、替换等。所有这些改变构成一个集合,这个集合被叫做一个transaction。
可以调用FragmentTransaction中的方法来处理这个transaction.
以这样得到FragmentTransaction类的实例: 
[java]  view plain copy
  1. FragmentManager fragmentManager = getFragmentManager();  
  2. FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();  

每个transaction是一组同时执行的变化的集合。用add(), remove(), replace()方法,把所有需要的变化加进去,然后调用commit()方法,将这些变化应用。在commit()方法之前,你可以调用addToBackStack(),把这个transaction加入back stack中去,这个back stack是由activity管理的,当用户按返回键时,就会回到上一个fragment的状态。下面的代码非常典型,用一个新的fragment取代之前的fragment,并且将之前的状态存储在back stack中。

[java]  view plain copy
  1. // Create new fragment and transaction  
  2. Fragment newFragment = new ExampleFragment();  
  3. FragmentTransaction transaction = getFragmentManager().beginTransaction();  
  4.   
  5. // Replace whatever is in the fragment_container view with this fragment,  
  6. // and add the transaction to the back stack  
  7. transaction.replace(R.id.fragment_container, newFragment);  
  8. transaction.addToBackStack(null);  
  9.   
  10. // Commit the transaction  
  11. transaction.commit();  
通过调用addToBackStack(),commit()的一系列转换作为一个transaction被存储在back stack中,用户按Back键可以返回上一个转换前的状态。
调用commit()方法并不能立即执行transaction中包含的改变动作,commit()方法把transaction加入activity的UI线程队列中。

下面我们对上述代码中出现的函数进行分析,以此来逐步学习Fragment的管理机制。

getSupportFragmentManager():

[java]  view plain copy
  1. public FragmentManager getSupportFragmentManager() {  
  2.     return mFragments;  
  3. }  
该函数返回类型是FragmentManager,FragmentManager是一个抽象类,其实现类是FragmentManager.FragmentManagerImpl

beginTransaction():
该函数在FragmentManagerIMpl中的源码如下:

[java]  view plain copy
  1. public FragmentTransaction beginTransaction() {  
  2.     return new BackStackRecord(this);  
  3. }  
返回一个BackStackRecord对象,该对象是FragmentTranscation的一个子类。
BackStackRecord的声明如下:

[java]  view plain copy
  1. final class BackStackRecord extends FragmentTransaction implements  
  2.         FragmentManager.BackStackEntry, Runnable {...}  
该类实现了一个重要的接口:FragmentManager.BackStackEntry, 该接口代表了fragment back stack的一个入口。可以用FragmentManager.getBackStackEntry()来检索BackStackEntry。    
接下来执行transaction.replace(), 查看BackStackRecord,调用过程源码如下:

[java]  view plain copy
  1. public FragmentTransaction replace(int containerViewId, Fragment fragment) {  
  2.     return replace(containerViewId, fragment, null);  
  3. }  
  4.   
  5. public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {  
  6.     if (containerViewId == 0) {  
  7.         throw new IllegalArgumentException("Must use non-zero containerViewId");  
  8.     }  
  9.   
  10.     doAddOp(containerViewId, fragment, tag, OP_REPLACE);  
  11.     return this;  
  12. }  
我们发现,replace()最终调用的函数为doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd), 将Fragment和对Fragment所进行的操作放到op链表中:

[java]  view plain copy
  1. private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {  
  2.     fragment.mFragmentManager = mManager;  
  3.   
  4.     if (tag != null) {  
  5.         if (fragment.mTag != null && !tag.equals(fragment.mTag)) {  
  6.             throw new IllegalStateException("Can't change tag of fragment "  
  7.                     + fragment + ": was " + fragment.mTag  
  8.                     + " now " + tag);  
  9.         }  
  10.         fragment.mTag = tag;  
  11.     }  
  12.   
  13.     if (containerViewId != 0) {  
  14.         if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {  
  15.             throw new IllegalStateException("Can't change container ID of fragment "  
  16.                     + fragment + ": was " + fragment.mFragmentId  
  17.                     + " now " + containerViewId);  
  18.         }  
  19.         fragment.mContainerId = fragment.mFragmentId = containerViewId;  
  20.     }  
  21.   
  22.     Op op = new Op();  
  23.     op.cmd = opcmd;  
  24.     op.fragment = fragment;  
  25.     addOp(op);  
  26. }  
该函数首先设置fragment的mFragmentManager属性,然后再设置其mContainerId和mFragmentId,最后创建Op对象,然设置相应自段,其中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;
每个字段的意思可直接通过英文名称获知。Op()类是BackStackRecord中声明的结构体,本质上是一个双向链表的Node。addOp()如下:

[java]  view plain copy
  1. void addOp(Op op) {  
  2.     if (mHead == null) {  
  3.         mHead = mTail = op;  
  4.     } else {  
  5.         op.prev = mTail;  
  6.         mTail.next = op;  
  7.         mTail = op;  
  8.     }  
  9.     op.enterAnim = mEnterAnim;  
  10.     op.exitAnim = mExitAnim;  
  11.     op.popEnterAnim = mPopEnterAnim;  
  12.     op.popExitAnim = mPopExitAnim;  
  13.     mNumOp++;  
  14. }  
该函数将Op对象添加到链表的末尾,并将mNumOp的值增一。

transaction.addToBackStack(null)设置了mAddToBackStack为true,源码如下:

[java]  view plain copy
  1. public FragmentTransaction addToBackStack(String name) {  
  2.     if (!mAllowAddToBackStack) {  
  3.         throw new IllegalStateException(  
  4.                 "This FragmentTransaction is not allowed to be added to the back stack.");  
  5.     }  
  6.     mAddToBackStack = true;  
  7.     mName = name;  
  8.     return this;  
  9. }  
此函数将mAddToBackStack自段设置为true,并设置mName字段。
最后调用transaction.commit()来执行transaction。commit()的调用过程代码如下:

[java]  view plain copy
  1. public int commit() {  
  2.     return commitInternal(false);  
  3. }  
  4.   
  5. int commitInternal(boolean allowStateLoss) {  
  6.     if (mCommitted) throw new IllegalStateException("commit already called");  
  7.     if (FragmentManagerImpl.DEBUG) {  
  8.         Log.v(TAG, "Commit: " + this);  
  9.         LogWriter logw = new LogWriter(TAG);  
  10.         PrintWriter pw = new PrintWriter(logw);  
  11.         dump("  "null, pw, null);  
  12.     }  
  13.     mCommitted = true;  
  14.     if (mAddToBackStack) {  
  15.         mIndex = mManager.allocBackStackIndex(this);  
  16.     } else {  
  17.         mIndex = -1;  
  18.     }  
  19.     mManager.enqueueAction(this, allowStateLoss);  
  20.     return mIndex;  
  21. }  
由于mAddToBackStack为true,所以会用FragmentManager为BackstackRecorder也即FragmentTransaction分配一个index,分配过程如下:

[java]  view plain copy
  1. public int allocBackStackIndex(BackStackRecord bse) {  
  2.     synchronized (this) {  
  3.         if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {  
  4.             if (mBackStackIndices == null) {  
  5.                 mBackStackIndices = new ArrayList<BackStackRecord>();  
  6.             }  
  7.             int index = mBackStackIndices.size();  
  8.             if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);  
  9.             mBackStackIndices.add(bse);  
  10.             return index;  
  11.   
  12.         } else {  
  13.             int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);  
  14.             if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);  
  15.             mBackStackIndices.set(index, bse);  
  16.             return index;  
  17.         }  
  18.     }  
  19. }  
FragmentManager用mAvailBackStackIndices和mBackStackIndices两个数组来为BackStackRecord分配Index。mAvailBackStackIndices用来存储在mBackStackIndices中能够分配的Index,mBackStackIndices则用来保存BackStackRecord。这利用两个数组可以减少对mBackStackIndices的动态分配大小的次数,是一个以空间换时间的策略。上面的代码首先判断是否有可用的Index分配给BackStackRecord,若无则直接将BackStackRecord插入到mBackStackIndices;若存在的话则从mAvailBackStackIndices的队尾取出一个index,然后设置mBackStackIndices中该index下的值。

让我们回到commit()中,该函数最后执行mManager.enqueAction(),源码如下:

[html]  view plain copy
  1. public void enqueueAction(Runnable action, boolean allowStateLoss) {  
  2.     if (!allowStateLoss) {  
  3.         checkStateLoss();  
  4.     }  
  5.     synchronized (this) {  
  6.         if (mDestroyed || mActivity == null) {  
  7.             throw new IllegalStateException("Activity has been destroyed");  
  8.         }  
  9.         if (mPendingActions == null) {  
  10.             mPendingActions = new ArrayList<Runnable>();  
  11.         }  
  12.         mPendingActions.add(action);  
  13.         if (mPendingActions.size() == 1) {  
  14.             mActivity.mHandler.removeCallbacks(mExecCommit);  
  15.             mActivity.mHandler.post(mExecCommit);  
  16.         }  
  17.     }  
  18. }  
[java]  view plain copy
  1. 该函数首先进行状态监测,查看该Fagment所在的Activity的生命周期是否处于Saving Activity之前,因为Activity保存状态往往是由用户离开那个Activity所造成的,在此之后执行commit会丢失一些状态信息。针对这种情况,可以使用commitAllowingStateLoss().最后将BackStackRecord加入到执行队列中。当第一次往执行  
  2. 队列中添加消息时,首先会从消息队列中所有callback属性为mExecCommit的消息删除,然后重新将mExecCommit添加到消息队列。mExecCommit的定义如下:  
[java]  view plain copy
  1. Runnable mExecCommit = new Runnable() {  
  2.     @Override  
  3.     public void run() {  
  4.         execPendingActions();  
  5.     }  
  6. };  
execPendingActions()只能在主线程内被调用,其内部通过一个循环对mPendingActions中的Actions进行执行。值得注意的是,每执行一次循环,mPendingActions中的所有Action都会被添加到一个临时数组中,然后这个数组被变量一遍以执行数组中的每个Runnable。同时,每个Runnable直接被调用了run,而不是开个线程执行的。当这个Runnable在执行的时候,mPendingActions数组可能会被添加内容。当某一时刻mPendingActions中的内容为空,则while循环退出。此部分代码如下:

[java]  view plain copy
  1. public boolean execPendingActions() {  
  2.     if (mExecutingActions) {  
  3.         throw new IllegalStateException("Recursive entry to executePendingTransactions");  
  4.     }  
  5.       
  6.     if (Looper.myLooper() != mActivity.mHandler.getLooper()) {  
  7.         throw new IllegalStateException("Must be called from main thread of process");  
  8.     }  
  9.   
  10.     boolean didSomething = false;  
  11.   
  12.     while (true) {  
  13.         int numActions;  
  14.           
  15.         synchronized (this) {  
  16.             if (mPendingActions == null || mPendingActions.size() == 0) {  
  17.                 break;  
  18.             }  
  19.               
  20.             numActions = mPendingActions.size();  
  21.             if (mTmpActions == null || mTmpActions.length < numActions) {  
  22.                 mTmpActions = new Runnable[numActions];  
  23.             }  
  24.             mPendingActions.toArray(mTmpActions);  
  25.             mPendingActions.clear();  
  26.             mActivity.mHandler.removeCallbacks(mExecCommit);  
  27.         }  
  28.         //一次性执行完数组中所有的Action  
  29.         mExecutingActions = true;  
  30.         for (int i=0; i<numActions; i++) {  
  31.             mTmpActions[i].run();  
  32.             mTmpActions[i] = null;  
  33.         }  
  34.         mExecutingActions = false;  
  35.         didSomething = true;  
  36.     }  
  37.       
  38.     if (mHavePendingDeferredStart) {  
  39.         boolean loadersRunning = false;  
  40.         for (int i=0; i<mActive.size(); i++) {  
  41.             Fragment f = mActive.get(i);  
  42.             if (f != null && f.mLoaderManager != null) {  
  43.                 loadersRunning |= f.mLoaderManager.hasRunningLoaders();  
  44.             }  
  45.         }  
  46.         if (!loadersRunning) {  
  47.             mHavePendingDeferredStart = false;  
  48.             startPendingDeferredFragments();  
  49.         }  
  50.     }  
  51.     return didSomething;  
  52. }  
由于BackstackRecorder实现了Runnable,我们来看看BackStackRecorder中的run(),如下所示:

[java]  view plain copy
  1. public void run() {  
  2.     if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);  
  3.   
  4.     if (mAddToBackStack) {  
  5.         if (mIndex < 0) {  
  6.             throw new IllegalStateException("addToBackStack() called after commit()");  
  7.         }  
  8.     }  
  9.   
  10.     bumpBackStackNesting(1);  
  11.   
  12.     Op op = mHead;  
  13.     //遍历op,根据cmd的类型对Fragment和FragmentManager进行相应的设置  
  14.     while (op != null) {  
  15.         switch (op.cmd) {  
  16.             case OP_ADD: {  
  17.                 Fragment f = op.fragment;  
  18.                 f.mNextAnim = op.enterAnim;  
  19.                 //将Fragment添加到FragmentManager中,其源码显示是将Fragment添加到FragmentManager中的mActive数组中,并将Fragment添加到了数组mAdded中。  
  20.                 mManager.addFragment(f, false);  
  21.             } break;  
  22.             case OP_REPLACE: {  
  23.                 Fragment f = op.fragment;  
  24.                 if (mManager.mAdded != null) {  
  25.                     //遍历已经添加的Fragment,  
  26.                     for (int i=0; i<mManager.mAdded.size(); i++) {  
  27.                         Fragment old = mManager.mAdded.get(i);  
  28.                         if (FragmentManagerImpl.DEBUG) Log.v(TAG,  
  29.                                 "OP_REPLACE: adding=" + f + " old=" + old);  
  30.                         //如果发现两个mContainerId一样,则进行特殊处理  
  31.                         if (f == null || old.mContainerId == f.mContainerId) {  
  32.                             if (old == f) {  
  33.                                 //两个Fragment一样,则置空,保留old中的Fragment  
  34.                                 op.fragment = f = null;  
  35.                             } else {  
  36.                                 // 将old fragment加入到 op.removed数组中,保留op中的Fragment  
  37.                                 if (op.removed == null) {  
  38.                                     op.removed = new ArrayList<Fragment>();  
  39.                                 }  
  40.                                 op.removed.add(old);  
  41.                                 old.mNextAnim = op.exitAnim;  
  42.                                 if (mAddToBackStack) {  
  43.                                     //设置old Fragment在BackStack中的Number  
  44.                                     old.mBackStackNesting += 1;  
  45.                                     if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "  
  46.                                             + old + " to " + old.mBackStackNesting);  
  47.                                 }  
  48.                                 //对old Fragment设置相应的状态属性,如mAdded、mRemoving, 从FragmentManager中移除oldFrgment的相关属性  
  49.                                 mManager.removeFragment(old, mTransition, mTransitionStyle);  
  50.                             }  
  51.                         }  
  52.                     }  
  53.                 }  
  54.                 //将Fragment添加到FragmentManager中  
  55.                 if (f != null) {  
  56.                     f.mNextAnim = op.enterAnim;  
  57.                     mManager.addFragment(f, false);  
  58.                 }  
  59.             } break;  
  60.             case OP_REMOVE:   
  61.             ......  
  62.         }  
  63.   
  64.         op = op.next;  
  65.     }  
  66.     //设置Fragment的当前状态,然后根据当前状态来回调Fragment的生命周期中的相关函数。此函数控制了Fragment的生命周期和Fragment的绘制,想要彻底理解Fragment的生命周期的同学可以认真研究此函数。  
  67.     mManager.moveToState(mManager.mCurState, mTransition,  
  68.             mTransitionStyle, true);  
  69.       
  70.     //将BackStackRecord加入到BackStack中,并回调onBackStackChanged  
  71.     if (mAddToBackStack) {  
  72.         mManager.addBackStackState(this);  
  73.     }  
  74. }  
addBackStackState()的源码如下:

[java]  view plain copy
  1. void addBackStackState(BackStackRecord state) {  
  2.     if (mBackStack == null) {  
  3.         mBackStack = new ArrayList<BackStackRecord>();  
  4.     }  
  5.     mBackStack.add(state);  
  6.     //回调onBackStackChanged  
  7.     reportBackStackChanged();  
  8. }  
可以看到传说中的BackStack就是在这里被创建的, FragmentManager中的BackStack主要是用来存储FragmentTransaction的。


小结:

FragmentTransaction中的Op链用来保存add、remove、replace等action,在FragmentTransaction的run执行时,Op链会被变量以调整每个节点的内容。

FragmentManager使用一个BackStack来管理FragmentTransaction;使用mAdded数组来添加被add的Fragment,Fragment的创建、显示等行为都受FragmentManager的控制。
FragmentManager中的moveToState()是一个非常重要的函数,在FragmentTransaction run的时候被调用。下次我们将深入这个函数。

你可能感兴趣的:(源码分析Fragmentd的BackStack管理过程)