Fragment 知识梳理(1) Fragment 源码解析

1、概述

官方是从3.0开始引入Fragment的,在文档中有对于其使用的详细介绍,能够看出来,在它刚出现时你们对于它是十分推崇的。然而随着使用Fragment开发的项目愈来愈多,在一些复杂场景下逐渐暴露出了它的一些问题,对因而否继续使用Fragment你们也有不一样的见解。目前在项目中也有大量以前留下来的使用 Fragment的代码, monkey有时会跑出一些莫名奇妙的问题,在这里咱们对于使用Fragment的好坏先不作评价,而是看看它内部整个的实现过程,学习它的思想,在之后出现问题的时候也方便排查,同时你们能够根据本身的需求来决定是否使用Fragmentjava

2、Fragment事务的执行过程

在操做Fragment时,第一件是就是经过ActivitygetFragmentManger()方法获得一个FragmentManager对象:bash

Fragment manager = getFragmentManager();
复制代码

咱们看一下Activity.java中的这个方法:ide

final FragmentController mFragments = FragmentController.createController(new HostCallbacks())

public FragmentManager getFragmentManager() {
    return mFragments.getFragmentManager();
}

class HostCallbacks extends FragmentHostCallback<Activity> {
    public HostCallbacks() {
        super(Activity.this);
    }
}
复制代码

能够看到getFragmentManager()调用的是FragmentController的接口,那么咱们再看看这个类对应的方法:oop

private final FragmentHostCallback<?> mHost;

public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
   return new FragmentController(callbacks)
}

private FragmentController(FragmentHostCallback<?> callbacks) {
    mHost = callbacks;
}

public FragmentManager getFragmentManager() {
   return mHost.getFragmentManagerImpl();
}
复制代码

原来FragmentController是把一个callback给包装了起来,真正完成任务的是FragmentHostCallback布局

final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();

FragmentManagerImpl getFragmentManagerImpl() {
    return mFragmentManagerImpl;
}
复制代码

那么结论就是咱们实际获得的是Activity#mFragments#mHost#mFragmentManagerImpl这个变量,获得这个实例以后,咱们经过它的beginTransition方法获得一个事务:post

FragmentTransation transation = manager.beginTransation();
复制代码

咱们看一下这个FragmentTransation到底是个什么东西,FragmentManagerImplFragmentManager的一个内部类,它实现了该接口:学习

final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {

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

}
复制代码

原来这个FragmentTransation也是一个接口,它的实现是BackStackRecord,而且在每次 beginTransaction时都是返回一个新的事务对象,包括以后进行的后退操做都是经过这个事务对象来管理的,这个对象中保存了建立它的FragmentManagerImpl实例。 BackStackRecord实际上是BackStackState的一个内部类,咱们平时就是经过它来进行add、remove、replace、attach、detach、hide、show等操做的,进入源码看一下这些操做背后都干了些什么:ui

final class BackStackRecord extends FragmentTransation implements FragmentManager.BackStackEntry, Runnable {

public FragmentTransation add(Fragment fragment, String tag) {
    doAddOp(0, fragment, tag, OP_ADD);
    return this;
}

public FragmentTransation add(int containerViewId, Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

public FragmentTransation add(int containerViewId, Fragment fragment, String tag) {
    doAddOp(containerViewId, fragment, tag, OP_ADD);
}

public FragmentTransation replace(int containerViewId, Fragment fragment) {
    return replace(containerViewId, fragment, null);
}

public FragmentTransation replace(int containerViewId, Fragment fragment, String tag) {
    if (containerViewId == 0) {
        //replace操做必需要指定containerViewId.
   }
   doAddOp(containerViewId, fragment, tag, OP_REPLACE);
}

public FragmentTransaction remove(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_REMOVE;
   op.fragment = fragment;
   addOp(op);
}

public FragmentTransaction hide(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_HIDE;
   op.fragment = fragment;
   addOp(op);
}

public FragmentTransaction show(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_SHOW;
   op.fragment = fragment;
   addOp(op);
}

public FragmentTransaction attach(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_ATTACH;
   op.fragment = fragment;
   addOp(op);
}

public FragmentTransaction detach(Fragment fragment) {
   Op op = new Op();
   op.cmd = OP_DETACH;
   op.fragment = fragment;
   addOp(op);
}

//新建一个操做,并给操做赋值。
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)) {
             //若是这个 fragment 以前已经有了tag,那么是不容许改变它的。
      }
      fragment.mTag = tag;
   }
   if (containerViewId != 0) {
        if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
            //若是这个fragment已经有了mFragmentId,那么不容许改变它。
       }
       fragment.mContainerId = fragment.mFragmentId = containerViewId;
   }
   Op op = new Op();
   op.cmd = opcmd;
   op.fragment = fragment;
   addOp(op);
}
//把操做添加到链表之中。
void addOp() {
    if (mHead == null) {
        mHead = mTail = op;
    } else {
       op.prev = mTail;
       mTail.next = op;
       mTail = op;
    }
    mNumOp++;
}
}
复制代码

看完上面这段代码,咱们能够获得下面这些信息:this

  • 咱们调用这些操做以后仅仅是把这个操做添加到了BackStackRecord当中的一个链表。
  • 在进行attach、detach、hide、show、remove这五个操做时是不须要传入containerViewId的,由于在执行这些操做以前这个Fragment必然已经通过了add操做,它的containerId是肯定的。
  • 在执行add操做时,须要保证FragmentmTagmContainerViewId在不为空时(也就是这个 Fragment实例以前已经执行过add操做),它们和新传入的tagcontainerViewId必须是相同的,这是由于在FragmentManagermActive列表中保存了全部被添加进去的Fragment,而其提供的 findFragmentById/Tag正是经过这两个字段做为判断的标准,所以不容许同一个实例在列表当中重复出现两次。
  • replace操做和add相似,它增长了一个额外条件,就是containerViewId不为空,由于replace须要知道它是对哪一个container进行操做,后面咱们会看到replace实际上是一个先removeadd的过程,所以`add 的那些判断条件一样适用。

那么这个链表中的操做何时被执行呢,看一下commit()操做:spa

public int commit() {
    return commitInternal(false);
}

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) {
        //已经有事务处理,抛出异常。
    }
    mCommited = true;
    if (mAddToBackState) {
         mIndex = mManager.allocBackStackIndex(this);
    } else {
         mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
}
复制代码

它最后调用了FragmentManagerenqueueAction方法,咱们进去看一下里面作了什么:

public void enqueueAction(Runnable action, boolean allowStateLoss) {    
    if (!allowStateLoss) {        
        checkStateLoss();    
    }    
    synchronized (this) {        
        if (mDestroyed || mHost == null) {            
           //若是Activity已经被销毁,那么抛出异常。          
        }       
        if (mPendingActions == null) {            
            mPendingActions = new ArrayList<Runnable>();        
        }
        //由于BackStackRecord实现了Runnable接口,把加入到其中。        
        mPendingActions.add(action);        
        if (mPendingActions.size() == 1) {        
           mHost.getHandler().removeCallbacks(mExecCommit);            
           mHost.getHandler().post(mExecCommit);        
        }   
    }
}

Runnable mExecCommit = new Runnable {
    public void run() {
        execPendingActions();
    }
}

public boolean execPendingActions() {
   if (mExecutingActions) {
      //已经有操做在执行,抛出异常
   }
   if (Looper.myLooper() != mHost.getHandler().getLooper()) {
       //不在主线程中执行,抛出异常
   }
   boolean didSomething = false;
   while (true) {
      int numActions;
      sychronized(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++) {
            //好吧,这里就又回调了BackStackRecord的run()方法
            mTmpActions[i].run();
            mTmpActions[i] = null;
       }
       mExecutingActions = false;
       didSomething = true; 
   }
}
复制代码
  • 在调用commit以后,把BackStackRecord加入到FragmentManagerImplmPendingActions中,并且经过查看FragmentManager的源码也能够发现,全部对mPendingActions的添加操做只有这一个地方调用,
  • 当其大小为1时,会经过主线程的Handler post一个Runnable mExecCommit出去,当这个Runnable执行时调用execPendingActions()方法。
  • execPendingActions它会拿出这个mPendingActions当中的全部Runnable执行(若是它是 BackStackRecord调用过来的,那么就是调用BackStackRecordrun方法),并把这个列表清空。在每一个BackStackRecordrun方法执行时,它是经过遍历BackStackRecord链表当中每一个节点的cmd来判断咱们以前经过FragmentTransation加入指望执行的那些操做的。
  • 能够看出execPendingActions这个方法很关键,由于它决定了咱们添加的操做何时会被执行,咱们看下还有那些地方调用到了它,为何要分析这个呢,由于咱们在项目当中发现不少来自于Fragment的异常都是由咱们后面谈论的moveToState方法抛出的,而moveToState执行的缘由是execPendingActions被调用了,所以了解它被调用的时机是咱们追踪问题的关键,关于调用的时机,咱们都总结在下面的注释当中了:
<!-- Activity.java -->
final void performStart() {
    mFragments.execPendingActions(); //有可能在 Activity 的 onStart 方法执行前
    mInstrumentation.callActivityOnStart(this);
}

final void performResume() {
    performRestart();
    mFragments.execPendingActions(); //若是是从 Stopped 过来的,那么有可能在 onStart 到 onResume 之间。
    ....
    mInstrumentation.callActivityOnResume(this);
    ....
    mFragments.dispatchResume(); 
    mFragments.execPendingActions(); //有可能在 onResume 到 onPause 之间。
}

<!-- FragmentManager.java -->
public void dispatchDestroy() { //这个调用在 onDestroy 以前。
    execPendingActions();
}

public boolean popBackStackImmediate() {
    executePendingTransactions();
}

public boolean popBackStackImmediate(String name, int flags) {
    executePendingTransactions();
}

复制代码

关于FragmentManager的讨论咱们先暂时放一放,看一下BackStackRecord是怎么执行链表内部的操做的:

public void run() {
    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) {
                    //遍历 mAdded列表,找到 containerId 相同的 old Fragment.
                    if (old == f) {
                        op.fragment = f = null;
                    } else {
                        if (op.removed == null) {
                             op.removed = new ArrayList<Fragment>();
                        }
                        op.removed.add(old); //这里要把replace以前的记下来是为了后退栈准备的。
                        if (mAddToBackStack) {
                             old.mBackStackNesting += 1;
                        }
                        mManager.removeFragment(old, transition, transitionStyle);
                    }
                }
                if (f != null) { 
                     f.addFragment(f, false);
                }
                break;
                //后面的remove,hide,show,attach,detach就是调用了FragmentManager中相应的方法,没什么特别的,就不贴出来了
                case xxx:
                   
            }
        }
        op = op.next;
    }
    //mCurState此时为FragmentManager当前的状态,其他的参数不用管。    
    mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); 
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    } 
}
复制代码

咱们来看一下FragmentManagerImpl对应的addFragment等操做:

public void addFragment(Fragment fragment, boolean moveToStateNow) {
   makeActive(fragment); //加入到mActive列表中。
   if (!fragment.mDetached) {
       if (mAdd.contains(fragment)) {
           //已经在mAdded列表,抛出异常。
       }
       mAdded.add(fragment);
       fragment.mAdded = true;
       fragment.mRemoving = false;
       if (moveToStateNow) {
           moveToState(fragment);
       }
   }
}

public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
    final boolean inactive = !fragment.isInBackStack();
    if (!fragment.mDetach || inactive) {
        if (mAdded != null) {
            mAdded.remove(fragment); //从mAdded列表中移除。
        }
        fragment.mAdded = false;
        fragment.mRemoving = true;
        //这里会根据是否加入后退栈来判断新的状态,最后会影响到Fragment生命周期的调用,若是是没有加入后退栈的,那么会多调用onDestroy、onDetach方法。
        moveToState(fragment, inactive ? Fragment.INITIALZING : Fragment.CREATED, transition, transitionStyle, false); 
    }
}

public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
    if (!fragment.mHidden) {
       fragment.mHidden = true;
       if (fragment.mView != null) {
          fragment.mView.setVisibility(View.GONE);
       }
    }
    fragment.onHiddenChanged(true);
}

public void showFragment(Fragment fragment, int transition, int transitionStyle) {
    if (fragment.mHidden) {
        fragment.mHidden = false;
        if (fragment.mView != null) {
             fragment.mView.setVisibility(View.VISIBLE);
        }
        fragment.onHiddenChanged(false);
    }
}

public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
    if (!fragment.mDetached) {
        fragment.mDetached = true;
        if (fragment.mAdded) {
             if (mAdded != null) {
                 mAdded.remove(fragment);
             }
             fragment.mAdded = false;
             moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
        }
    }
}

public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
    if (fragment.mDetached) {
         if (!fragment.mAdded) {
              if (mAdded.contains(fragment)) {
                  //mAdded列表中已经有,抛出异常,
              }
              mAdded.add(fragment);
              fragment.mAdded = true;
              moveToState(fragment, mCurState, transition, transitionStyle, false);
         }
    }

}
复制代码

这里的操做不少,咱们须要明白如下几点:

  • mActivemAdded的区别:mActive表示执行过add操做,而且其没有被移除(移除表示的是在不加入后退栈的状况下被removeFragment),全部被动改变Fragment状态的调用都是遍历这个列表;而 mAdded则表示执行过add操做,而且没有执行detachFragment/removeFragment,也就是说Fragment 是存在容器当中的,可是有多是被隐藏的(hideFragment)。
  • attachFragment 必须保证其状态是 mDetach 的,而该属性的默认值是 false,只有在执行过 detach 方法后,才能执行,执行它会把 f.mView 从新加入到 container 中。
  • detachFragment 会把 f.mViewcontainer 中移除。
  • removeFragmentdetachFragment 会强制改变 Fragment 的状态,这是由于它们须要改变 Fragment 在布局中的位置,而这经过被动地接收 FragmentManager 状态(即所在Activity的状态)是没法实现的。在 removeFragment 时,会根据是否加入后退栈来区分,若是假如了后退栈,由于有可能以后会回退,而回退时遍历的是 mActive 列表,若是把它的状态置为Fragment.INITIALZING,那么在 moveToState方法中就会走到最后一步,把它从mActive列表中移除,就找不到了也就没法恢复,所以这种状况下Fragment最终的状态的和detachFragment是相同的。
  • 在加入后退栈时,detachFragment 时,会把 mDetach置为true,这种状况下以后能够执行 attachFragment操做但不能执行 addFragment操做;removeFragment 以后能够执行 addFragment操做但不能执行 attachFragment操做。
  • showFragmenthideFragment 并不会主动改变 Fragment 的状态,它仅仅是回调 onHiddenChanged方法,其状态仍是跟着 FragmentManager 来走。
mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); 
复制代码

这个方法才是 Fragment的核心,它的思想就是根据 Fragment 指望进入的状态和以前的状态进行对比,从而调用 Fragment相应的生命周期,那么问题就来,什么是指望进入的状态呢,我认为能够这么理解:

  • 用户没有进行主动操做,可是 FragmentFragmentManager的状态不一致,这时须要发生变化。
  • 用户进行了主动操做,不管FragmentFragmentManager的状态是否一致,由于 Fragment 的状态发生了变化,所以这时也须要执行。

这里咱们为了简便起见先看一下和生命周期有关的代码:

static final int INITIALIZING = 0;     // Not yet created.
static final int CREATED = 1;          // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3;          // Fully created, not started.
static final int STARTED = 4;          // Created and started, not resumed.
static final int RESUMED = 5;          // Created started and resumed.

void moveToState(int newState, int transit, int transitStyle, boolean always) {
   if (!always && mCurState == newState) {
      return;
   }
   mCurState = newState;
   if (mActive != null) {
       for (int i = 0; i < mActive.size; i++) {
           //在addFragment中经过makeActive加入进去
           Fragment f = mActive.get(i);
           moveToState(f, newState, transit, transitStyle, false);
       }
   }
}

void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) {
    if (f.mState < newState) { //新的状态高于当前状态
        switch(f.mState) {
             case Fragment.INITIALZING:
                 f.onAttach(mHost.getContext());
                 if (f.mParentFragment == null) {
                     mHost.onAttachFragment(f);
                 }
                 if (!f.mRetaining) {
                     f.performCreate(f.mSavedFragmentState);
                 }
                 if (f.mFromLayout) {
                     f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState);
                     if (f.mHidden) f.mView.setVisibility(View.GONE);
                     f.onViewCreated(f.mView, f.mSavedFragmentState);
                 }
             case Fragment.CREATED:
                  if (newState > Fragment.CREATED) {
                      if (!f.mFromLayout) {
                          ViewGroup container = null;
                          if (f.mCotainerId != null) {
                               cotainer = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                               if (container == null && !f.mRestored) {
                                  //no view found
                               }
                          }
                          f.mContainer = container;
                          f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState); 
                          if (f.mView != null) {
                               f.mInnerView = f.mView;
                               if (Build.VERSION.SDK >= 11) {
                                   ViewCompact.setSaveFromParentEnable(f.mView, false);
                               } else {
                                   f.mView = NoSaveStateFrameLayout.wap(f.mView);
                               }
                               if (f.mHidden) f.mView.setVisibility(View.GONE);
                               f.onViewCreated(f.mView, f.mSavedFragmentState);
                          } else {
                               f.mInnerView = null;
                          }
                      }
                      f.performActivityCreated(f.mSavedFragmentState);
                  }
             case Fragment.ACTIVITY_CRREATED:
             case Fragment.STOPPED:
                 if (newState > Fragment.STOPPED) {
                      f.performStart();
                 }
             case Fragment.STARTED:
                 if (newState > Fragment.STARTED) {
                      f.performResume();
                 }
        }
    } else if (f.mState > newState) { //新的状态低于当前状态
        switch(f.mState) {
            case Fragment.RESUMED:
                if (newState < Fragment.RESUMED) {
                    f.performPause();
                }
            case Fragment.STARTED:
                if (newState < Fragment.STARTED) {
                    f.performStop();
                }
            case Fragment.STOPPED::
                if (newState < Fragment.STOPPED) {
                    f.performReallyStop();
                }
            case Fragment.ACTIVITY_CREATED:
                if (newState < Fragment.ACTIVITY_CREATED) {
                    f.performDestroyView(); //调用onDestory()
                    if (f.mView != null && f.mContainer != null) {
                        f.mContainer.removeView(f.mView); //把Fragment的View从视图中移除。
                   }
                }
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                      if (f.mAnimationAway != null) {
                          ...
                      } else {
                           if (!f.mRetaining) {
                               f.performDestory();
                           } else {
                              f.mState = Fragment.INITIALIZING;
                           }
                           f.onDetach();
                           if (!f.mRetaining) {
                               makeInActive(f);//把Fragment从mActive中移除,并把Fragment的全部状态恢复成初始状态,至关于它是一个全新的Fragment。
                           } else {
                               f.mHost = null;
                               f.mParentFragment = null;
                               f.mFragmentManager = null;
                               f.mChildFragmentManager = null;
                           }
                      }
                }
        }
}
复制代码

moveToState方法中,咱们看到了许多熟悉的面孔,就是咱们平时最常谈到的 Fragment 的生命周期,经过这段代码咱们就能够对它的生命周期有更加直观的理解。

相关文章
相关标签/搜索