Fragment-Transaction 源码分析

概述

这篇文章的简要分析了Activity中的Transaction和add,replace等操作以及backstack的工作原理。

 

分析transaction源码的原因是因为我在写一个测试代码的时候,发现replace并没有将之前所有添加到某个container id上的Fragment全部移除掉,觉得很奇怪。

 

查看官方API对replace的解释

Replace an existing fragment that was addedto a container. This is essentially the same as calling remove(Fragment) forall currently added fragments that were added with the same containerViewId andthen add(int,Fragment, String) with the same arguments given here.

 

怎么会和我测试的结果不一样,于是开始查看源代码。最后发现应该是一个Bug,然后将这个bug report在https://code.google.com/p/android/issues/detail?id=68856&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

 

看看是我理解得不透彻还是确实算个Bug,哈哈。

 

要测试的内容如下

首先我们以下面这段代码为例,来分析Fragment的add操作

点击一个Button的时候执行下面的操作

FragmentTransaction ft =getFragmentManager().beginTransaction();

 

ft.add(R.id.container,FragmentA.newInstance("1"));

ft.add(R.id.container,FragmentA.newInstance("2"));

ft.add(R.id.container,FragmentA.newInstance("3"));

ft.add(R.id.container,FragmentA.newInstance("4"));

ft.add(R.id.container,FragmentA.newInstance("5"));

ft.add(R.id.container,FragmentA.newInstance("6"));

ft.add(R.id.container,FragmentA.newInstance("7"));

 

ft.addToBackStack(null);

ft.commit();

接着点击另外一个按钮执行下面的操作:

FragmentTransaction ft =getFragmentManager().beginTransaction();

ft.replace(R.id.container,FragmentA.newInstance("replaced A"));

ft.addToBackStack(null);

ft.commit();

getFragmentManager

进入Activity的源码,我们发现Activity中有个FragmentManagerImpl,这个实例用来管理Fragment的添加,删除,以及保存当前的激活的Fragment,等。

 

Activity类

 

final FragmentManagerImpl mFragments = newFragmentManagerImpl();

public FragmentManager getFragmentManager() {

returnmFragments;

}

 

beginTransaction

当我们调用beginTransaction的时候,FragmentManager会为我们生成一个transaction,这个transaction其实是一个保存你即将进行的一些列操作的栈。比如你要add一个Fragment,接着又要replace一个Fragment,这两个操作都会被当做两个操作顺序的记录在这个transaction中。根据名字也可以看出来
(BackStackRecord,是一个实现了FragmentTransaction的类),

 

FragmentManagerImpl 类

 

ArrayList<BackStackRecord> mBackStackIndices;

@Override

public FragmentTransaction beginTransaction() {

    return newBackStackRecord(this);

}

 

FragmentManager.add

接着我们调用了ft.add(R.id.cntainer, FragmentA.newInstance("1"));,这个操作将会向新生成的BackStackRecord对象中添加一个操作事件,即Op对象。Op对象相当于一个双向链表,记录了前一个操作和后一个操作。比如我们这次add了7个FragmentA,那么这7个操作会当成7个Op存放在这个新生成的BackStackRecord(就是一个Transaction)中。

 

  public FragmentTransaction add(intcontainerViewId, Fragment fragment, String tag) {

       doAddOp(containerViewId, fragment, tag, OP_ADD);

        returnthis;

    }

    

private void doAddOp(int containerViewId, Fragmentfragment, 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 offragment "

                        + fragment + ":was " + fragment.mFragmentId

                        + " now " +containerViewId);

            }

           fragment.mContainerId = fragment.mFragmentId = containerViewId;

        }

               //关键代码:生成Op来记录这次操作。

        Op op =new Op();

        op.cmd= opcmd;

       op.fragment = fragment;

       addOp(op);

    }

     //关键代码:将Op添加到新生成的这个BackStackRecord中,会将这次trascation事件中的每个Op顺序的记录下来。

    voidaddOp(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++;

    }

 

 

  static finalclass Op {

        Opnext;

        Opprev;

        intcmd;

       Fragment fragment;

        intenterAnim;

        intexitAnim;

        intpopEnterAnim;

        intpopExitAnim;

        ArrayList<Fragment> removed;

    }

    

紧接着,我们调用了ft.addToBackStack(null);

  publicFragmentTransaction addToBackStack(String name) {

        if(!mAllowAddToBackStack) {

           throw new IllegalStateException(

                   "This FragmentTransaction is not allowed to be added to the backstack.");

        }

//关键代码:将mAddToBackStack设置成true,这会在commit的时候判断,以便于将这个transaction添加到FragmentManager的Back stack栈中

       mAddToBackStack = true;

        mName =name;

        returnthis;

}

 

FragmentManager.commit

 最后,我们调用了ft.commit(),然后,FragmentManager就会将这次的所有Op放到主线程中去按顺序执行。BackStackRecord实现了run方法,所以在主线程执行的时候会调用run方法中的代码。

    public int commit() {

        returncommitInternal(false);

    }

    

    intcommitInternal(boolean allowStateLoss) {

        if(mCommitted) throw new IllegalStateException("commit alreadycalled");

        if(FragmentManagerImpl.DEBUG) {

           Log.v(TAG, "Commit: " + this);

           LogWriter logw = new LogWriter(TAG);

           PrintWriter pw = new PrintWriter(logw);

           dump("  ", null, pw,null);

        }

       mCommitted = true;

//关键代码:判断是否需要添加到Back stack

        if(mAddToBackStack) {

           mIndex = mManager.allocBackStackIndex(this);

        } else{

           mIndex = -1;

        }

       //关键代码:将这个transaction放入到FragmentManager的执行队列中去,当要开始执行这个transaction的时候,就会调用到BackStackRecord的run方法。

       mManager.enqueueAction(this, allowStateLoss);

        returnmIndex;

    }

    

这里,我们看看FragmentManager的allocBackStackIndex方法。我们发现FragmentManger的back stack就是一个ArrayList,里面记录了一些列的transaction。

 

publicint allocBackStackIndex(BackStackRecord bse) {

        synchronized (this) {

            if (mAvailBackStackIndices == null|| mAvailBackStackIndices.size() <= 0) {

                if (mBackStackIndices == null){

//关键代码:生成Back stack的list

                    mBackStackIndices = newArrayList<BackStackRecord>();

                }

                int index =mBackStackIndices.size();

                if (DEBUG) Log.v(TAG,"Setting back stack index " + index + " to " + bse);

//关键代码:添加这次的transaction到Backstack的list

                mBackStackIndices.add(bse);

                return index;

 

            } else {

                int index =mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);

                if (DEBUG) Log.v(TAG,"Adding back stack index " + index + " with " + bse);

                mBackStackIndices.set(index, bse);

                return index;

            }

        }

    }

    

 

Add,replace源码

继续刚才的情况,在commit之后,会把这次的transaction放到FragmentManager的执行队列中去,当开始执行这个Transaction的时候,会调用到这个BackStackRecord的run方法。这个方法中会顺序的调用这个BackStackRecord中的所有Op,我们刚才已经分析指导,每个add,remove等操作都当做Op存放在这个Transaction中,BackStackRecord就是一个Transaction的实例。在处理一个Op的时候,会根据这个Op的cmd属性来进行add,remove,replace等操作。

    publicvoid run() {

        if (FragmentManagerImpl.DEBUG)Log.v(TAG, "Run: " + this);

 

        if (mAddToBackStack) {

            if (mIndex < 0) {

                throw newIllegalStateException("addToBackStack() called after commit()");

            }

        }

 

        bumpBackStackNesting(1);

 

        Op op = mHead;

//关键代码:顺序处理这个transaction中的所有op

        while (op != null) {

//关键代码:根据op的cmd属性分别进行add,replace等操作

            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) {

//关键代码:我们这篇文章的重点来了,为什么只移除掉了一部分的Fragment呢?在这个For循环中,本来目的是要找出所有添加到这个mContainerId上的所有的Fragment,将他们从FragmentManager管理的mAdded表(这个表记录了Add到这个Activity的Fragment)中移除。但是我们看到在for循环里,i在不断的增加,但是实际上当从mManager .mAdded移除掉一个Fragment的时候,这个i的位置已经不对了。比如最开始我们的mAdded里面有序号为1,2,3,4,5,6,7的Fragment,在i

==0的时候,移除掉了序号为1的Fragment,所以mAdded里面还有序号为2,3,4,5,6,7的Fragment。接着i==1的时候,移除序号为3的Fragment。依次类推,序号为2,4,6的Fragment就没有被移除掉,所以就出现了文章开头处的问题。

                        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 = newArrayList<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 newIllegalArgumentException("Unknown cmd: " + op.cmd);

                }

            }

 

            op = op.next;

        }

 

        mManager.moveToState(mManager.mCurState,mTransition,

                mTransitionStyle, true);

 

//关键代码:将这个Transaction添加到backstack中去。

        if (mAddToBackStack) {

            mManager.addBackStackState(this);

        }

}

 

按back回退

按back首先调用的是Activity的onBackPressed

public void onBackPressed() {

//关键代码:让Activity的backstack处理,如果返回false,表示没有需要back的,所以当前activity就finish掉。

        if(!mFragments.popBackStackImmediate()) {

           finish();

        }

}

接着会去到FragmentManager的popBackStackImmediate

 

public boolean popBackStackImmediate() {

       checkStateLoss();

       executePendingTransactions();

        returnpopBackStackState(mActivity.mHandler, null, -1, 0);

}

 

 

   booleanpopBackStackState(Handler handler, String name, int id, int flags) {

        if(mBackStack == null) {

           return false;

        }

        if(name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE)== 0) {

            intlast = mBackStack.size()-1;

            if(last < 0) {

               return false;

            }

            

finalBackStackRecord bss = mBackStack.remove(last);

//关键代码:从FragmentManager管理的backstack中取出一个transaction(就是我们刚才说的BackStackRecord),调用他的popFromBackStack来还原之前的状态。

           bss.popFromBackStack(true);

           reportBackStackChanged();

        } else{

            intindex = -1;

            if(name != null || id >= 0) {

               // If a name or ID is specified, look for that place in

               // the stack.

               index = mBackStack.size()-1;

               while (index >= 0) {

                   BackStackRecord bss = mBackStack.get(index);

                   if (name != null && name.equals(bss.getName())) {

                        break;

                   }

                   if (id >= 0 && id == bss.mIndex) {

                        break;

                   }

                   index--;

               }

                if (index < 0) {

                   return false;

               }

               if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {

                   index--;

                   // Consume all following entries that match.

                   while (index >= 0) {

                        BackStackRecord bss =mBackStack.get(index);

                        if ((name != null&& name.equals(bss.getName()))

                                || (id >= 0&& id == bss.mIndex)) {

                           index--;

                            continue;

                        }

                        break;

                   }

               }

            }

            if(index == mBackStack.size()-1) {

               return false;

            }

           final ArrayList<BackStackRecord> states

                   = new ArrayList<BackStackRecord>();

            for(int i=mBackStack.size()-1; i>index; i--) {

               states.add(mBackStack.remove(i));

            }

           final int LAST = states.size()-1;

            for(int i=0; i<=LAST; i++) {

               if (DEBUG) Log.v(TAG, "Popping back stack state: " +states.get(i));

               states.get(i).popFromBackStack(i == LAST);

            }

           reportBackStackChanged();

        }

        returntrue;

}

 

紧接着我们看看BackStackRecord是怎么来处理的

 

publicvoid popFromBackStack(boolean doStateMove) {

        if (FragmentManagerImpl.DEBUG) {

            Log.v(TAG, "popFromBackStack:" + this);

            LogWriter logw = new LogWriter(TAG);

            PrintWriter pw = newPrintWriter(logw);

            dump("  ", null, pw, null);

        }

 

        bumpBackStackNesting(-1);

 

//关键代码:在这里又开始循环取出这个transaction中的Op(就是那些add,replace等操作)。然后做出一些跟刚才add,replace相反的操作.

 

        Op op = mTail;

        while (op != null) {

            switch (op.cmd) {

//关键代码:如果之前这个Transaction是Add操作,那么我们就用FragmentManager来将这个Fragment移除掉。

                case OP_ADD: {

                    Fragment f = op.fragment;

                    f.mNextAnim =op.popExitAnim;

                    mManager.removeFragment(f,

                           FragmentManagerImpl.reverseTransit(mTransition),

                            mTransitionStyle);

                } break;

              //关键代码:如果之前是Replace操作,我们就将之前在Replace操作的时候remove掉得那些Fragment再次add进来 

caseOP_REPLACE: {

                    Fragment f = op.fragment;

                    if (f != null) {

                        f.mNextAnim =op.popExitAnim;

                       mManager.removeFragment(f,

                                FragmentManagerImpl.reverseTransit(mTransition),

                               mTransitionStyle);

                    }

                    if (op.removed != null) {

                        for (int i=0;i<op.removed.size(); i++) {

                            Fragment old = op.removed.get(i);

                            old.mNextAnim =op.popEnterAnim;

                           mManager.addFragment(old, false);

                        }

                    }

                } break;

                case OP_REMOVE: {

                    Fragment f = op.fragment;

                    f.mNextAnim =op.popEnterAnim;

                    mManager.addFragment(f,false);

                } break;

                case OP_HIDE: {

                    Fragment f = op.fragment;

                    f.mNextAnim =op.popEnterAnim;

                    mManager.showFragment(f,

                           FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);

                } break;

                case OP_SHOW: {

                    Fragment f = op.fragment;

                    f.mNextAnim =op.popExitAnim;

                    mManager.hideFragment(f,

                           FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);

                } break;

                case OP_DETACH: {

                    Fragment f = op.fragment;

                    f.mNextAnim =op.popEnterAnim;

                    mManager.attachFragment(f,

                           FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);

                } break;

                case OP_ATTACH: {

                    Fragment f = op.fragment;

                    f.mNextAnim =op.popEnterAnim;

                    mManager.detachFragment(f,

                            FragmentManagerImpl.reverseTransit(mTransition),mTransitionStyle);

                } break;

                default: {

                    throw newIllegalArgumentException("Unknown cmd: " + op.cmd);

                }

            }

 

            op = op.prev;

        }

 

        if (doStateMove) {

           mManager.moveToState(mManager.mCurState,

                   FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle,true);

        }

 

        if (mIndex >= 0) {

            mManager.freeBackStackIndex(mIndex);

            mIndex = -1;

        }

    }

 

 
 
posted @ 2016-08-02 14:49  Daisy-程序媛  阅读(409)  评论(0编辑  收藏  举报