FragmentManager详解

       很久没去用fragment了,渐渐的开始忘记了。今天恰好遇见同事使用fragment,导致程序发生崩溃,因此我重新对fragment进行了分析。我会通过我解决问题的方式,将我理解fragment的思路,告诉大家。
     
     首先,我先按照自己的理解,写了这样一段代码,用于fragment切换。
    
FragmentManager mManager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
   
Fragment fragment = manager.findFragmentByTag(tag);
if(fragment!=null){
 transaction.attach(fragment);
}else{
 transaction.add(R.id.container,fragment,tag);
}
transaction.commit();
      上面这段代码,参考了一些资料,自己对这段代码还是抱有一些疑问:

1.FragmentManager是什么?
2.beginTransaction(),如何得到FragmentTransaction的?
3.FragmentTransaction 的attach  add这些方法,都是做了什么操作?

     然后,我就带着这些疑问,开始翻源码了。
     首先,我们先查看FragmentManager:

FragmentManager
    
public abstract class FragmentManager 

      FragmentManager是抽象类,定义了很多方法。具体的实现,在于它的内部类
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory
因此,FragmentManager的操作,大部分都在FragmentManagerImpl中。
      我们先看beginTransaction()方法:

  public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }

      FragmentTransaction其实是BackStackRecord的实例,我猜想,BackStackRecord是FragmentTransaction的子类,可以肯定,FragmentTransaction的操作,实际上是BackStackRecord的实现的。
不要着急,后面将会分析BackStackRecord。
      然后,我们看findFragmentByTag():
 
  public Fragment findFragmentByTag(String tag) {
        if (mAdded != null && tag != null) {
            // First look through added fragments.
            for (int i=mAdded.size()-1; i>=0; i--) {
                Fragment f = mAdded.get(i);
                if (f != null && tag.equals(f.mTag)) {
                    return f;
                }
            }
        }
        if (mActive != null && tag != null) {
            // Now for any known fragment.
            for (int i=mActive.size()-1; i>=0; i--) {
                Fragment f = mActive.get(i);
                if (f != null && tag.equals(f.mTag)) {
                    return f;
                }
            }
        }
        return null;
    }

      mAdded和mActive,是两个ArrayList<Fragment>,它们的作用,分别是来保存通过transaction.add和所有的fragment,在这个方法中,先对mAdded进行查找,没有查找到,再到mActive中查找,查找tag对应的fragment。如果存在,我们将调用FragmentTransaction的attach方法。
       接下来,我们分析这个attach方法。前面说到,FragmentTransaction实例,是有BackStackRecord实例化得到的。因此,我们直接去BackStackRecord查看attach方法,可以发现,BackStackRecord的方法,基本和FragmentTransaction的方法一致。打开attach方法:
      
 public FragmentTransaction attach(Fragment fragment) {
        Op op = new Op();
        op.cmd = OP_ATTACH;
        op.fragment = fragment;
        addOp(op);

        return this;
    }
      Op是什么呢?
    
 static final class Op {
        Op next;
        Op prev;
        int cmd;
        Fragment fragment;
        int enterAnim;
        int exitAnim;
        int popEnterAnim;
        int popExitAnim;
        ArrayList<Fragment> removed;
    }
      Op是静态内部类,通过命名,我们可以知道,BackStackRecord其实是通过链表实现的栈。Op是节点,保存了Fragment的相关信息。    最后,attach方法在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++;
    }
      
       添加一个节点,数量++;
     
     最后一个方法,commit().
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最终调用的是mManager.enqueueAction(this, allowStateLoss);转来转去,最后还是回到了FragmentManager的方法,那我们就看看enqueueAction这个方法吧。
      这个方法名称,就是把动作放到队列里面去,事实上,每个BackStackRecord相当于一个动作,就是每次beginTransaction,其实就是在构建一次动作,最后commit就是添加到队列里,然后得到执行。

        到最后,执行动作的类,是FragmentManager的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;
        }
        
        if (mHavePendingDeferredStart) {
            boolean loadersRunning = false;
            for (int i=0; i<mActive.size(); i++) {
                Fragment f = mActive.get(i);
                if (f != null && f.mLoaderManager != null) {
                    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                }
            }
            if (!loadersRunning) {
                mHavePendingDeferredStart = false;
                startPendingDeferredFragments();
            }
        }
        return didSomething;
    }
        看到Looper,我们应该知道动作的处理方式了。然后,后面是个while的死循环, mTmpActions[i].run();是方法的核心,它的实现来自BackStackRecord。为什么这么说,因为BackStackRecord是通过enqueueAction添加到list中,最后到了 mTmpActions中,所以,mTmpActions[i].run();调用的还是BackStackRecord的run(),我们按照预期的想法,确实在BackStackRecord中找到了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);

        TransitionState state = null;
        SparseArray<Fragment> firstOutFragments = null;
        SparseArray<Fragment> lastInFragments = null;
        if (SUPPORTS_TRANSITIONS) {
            firstOutFragments = new SparseArray<Fragment>();
            lastInFragments = new SparseArray<Fragment>();

            calculateFragments(firstOutFragments, lastInFragments);

            state = beginTransition(firstOutFragments, lastInFragments, false);
        }

        int transitionStyle = state != null ? 0 : mTransitionStyle;
        int transition = state != null ? 0 : mTransition;
        Op op = mHead;
        while (op != null) {
            int enterAnim = state != null ? 0 : op.enterAnim;
            int exitAnim = state != null ? 0 : op.exitAnim;
            switch (op.cmd) {
                case OP_ADD: {
                    Fragment f = op.fragment;
                    f.mNextAnim = 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 = exitAnim;
                                    if (mAddToBackStack) {
                                        old.mBackStackNesting += 1;
                                        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
                                                + old + " to " + old.mBackStackNesting);
                                    }
                                    mManager.removeFragment(old, transition, transitionStyle);
                                }
                            }
                        }
                    }
                    if (f != null) {
                        f.mNextAnim = enterAnim;
                        mManager.addFragment(f, false);
                    }
                } break;
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                    f.mNextAnim = exitAnim;
                    mManager.removeFragment(f, transition, transitionStyle);
                } break;
                case OP_HIDE: {
                    Fragment f = op.fragment;
                    f.mNextAnim = exitAnim;
                    mManager.hideFragment(f, transition, transitionStyle);
                } break;
                case OP_SHOW: {
                    Fragment f = op.fragment;
                    f.mNextAnim = enterAnim;
                    mManager.showFragment(f, transition, transitionStyle);
                } break;
                case OP_DETACH: {
                    Fragment f = op.fragment;
                    f.mNextAnim = exitAnim;
                    mManager.detachFragment(f, transition, transitionStyle);
                } break;
                case OP_ATTACH: {
                    Fragment f = op.fragment;
                    f.mNextAnim = enterAnim;
                    mManager.attachFragment(f, transition, transitionStyle);
                } break;
                default: {
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                }
            }

            op = op.next;
        }

        mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);

        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        }
    }

      结论就出来了,其实FragmentTransaction调用的方法,还是FragmentManagerImpl的方法。通过上面,一系列的过程,我们发现,通过这样的复杂的设计,才保证了Fragment的调用的正确性。大家,通过我翻查源码的过程,应该也理解了FragmentManager的设计了。是不是很有帮助呢?

       


你可能感兴趣的:(Fragment,Fragment切换)