官方是从3.0
开始引入Fragment
的,在文档中有对于其使用的详细介绍,能够看出来,在它刚出现时你们对于它是十分推崇的。然而随着使用Fragment
开发的项目愈来愈多,在一些复杂场景下逐渐暴露出了它的一些问题,对因而否继续使用Fragment
你们也有不一样的见解。目前在项目中也有大量以前留下来的使用 Fragment
的代码, monkey
有时会跑出一些莫名奇妙的问题,在这里咱们对于使用Fragment
的好坏先不作评价,而是看看它内部整个的实现过程,学习它的思想,在之后出现问题的时候也方便排查,同时你们能够根据本身的需求来决定是否使用Fragment
。java
Fragment
事务的执行过程在操做Fragment
时,第一件是就是经过Activity
的getFragmentManger()
方法获得一个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
到底是个什么东西,FragmentManagerImpl
是FragmentManager
的一个内部类,它实现了该接口:学习
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
操做时,须要保证Fragment
的mTag
和mContainerViewId
在不为空时(也就是这个 Fragment
实例以前已经执行过add
操做),它们和新传入的tag
和containerViewId
必须是相同的,这是由于在FragmentManager
的mActive
列表中保存了全部被添加进去的Fragment
,而其提供的 findFragmentById/Tag
正是经过这两个字段做为判断的标准,所以不容许同一个实例在列表当中重复出现两次。replace
操做和add
相似,它增长了一个额外条件,就是containerViewId
不为空,由于replace
须要知道它是对哪一个container
进行操做,后面咱们会看到replace
实际上是一个先remove
再add
的过程,所以`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);
}
复制代码
它最后调用了FragmentManager
的enqueueAction
方法,咱们进去看一下里面作了什么:
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
加入到FragmentManagerImpl
的mPendingActions
中,并且经过查看FragmentManager
的源码也能够发现,全部对mPendingActions
的添加操做只有这一个地方调用,Handler post
一个Runnable mExecCommit
出去,当这个Runnable
执行时调用execPendingActions()
方法。execPendingActions
它会拿出这个mPendingActions
当中的全部Runnable
执行(若是它是 BackStackRecord
调用过来的,那么就是调用BackStackRecord
的run
方法),并把这个列表清空。在每一个BackStackRecord
的run
方法执行时,它是经过遍历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);
}
}
}
复制代码
这里的操做不少,咱们须要明白如下几点:
mActive
和mAdded
的区别:mActive
表示执行过add
操做,而且其没有被移除(移除表示的是在不加入后退栈的状况下被removeFragment
),全部被动改变Fragment
状态的调用都是遍历这个列表;而 mAdded
则表示执行过add
操做,而且没有执行detachFragment/removeFragment
,也就是说Fragment
是存在容器当中的,可是有多是被隐藏的(hideFragment
)。attachFragment
必须保证其状态是 mDetach
的,而该属性的默认值是 false
,只有在执行过 detach
方法后,才能执行,执行它会把 f.mView
从新加入到 container
中。detachFragment
会把 f.mView
从 container
中移除。removeFragment
和 detachFragment
会强制改变 Fragment
的状态,这是由于它们须要改变 Fragment
在布局中的位置,而这经过被动地接收 FragmentManager
状态(即所在Activity
的状态)是没法实现的。在 removeFragment
时,会根据是否加入后退栈来区分,若是假如了后退栈,由于有可能以后会回退,而回退时遍历的是 mActive
列表,若是把它的状态置为Fragment.INITIALZING
,那么在 moveToState
方法中就会走到最后一步,把它从mActive
列表中移除,就找不到了也就没法恢复,所以这种状况下Fragment
最终的状态的和detachFragment
是相同的。detachFragment
时,会把 mDetach
置为true
,这种状况下以后能够执行 attachFragment
操做但不能执行 addFragment
操做;removeFragment
以后能够执行 addFragment
操做但不能执行 attachFragment
操做。showFragment
和 hideFragment
并不会主动改变 Fragment
的状态,它仅仅是回调 onHiddenChanged
方法,其状态仍是跟着 FragmentManager
来走。mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true);
复制代码
这个方法才是 Fragment
的核心,它的思想就是根据 Fragment
指望进入的状态和以前的状态进行对比,从而调用 Fragment
相应的生命周期,那么问题就来,什么是指望进入的状态呢,我认为能够这么理解:
Fragment
和 FragmentManager
的状态不一致,这时须要发生变化。Fragment
和 FragmentManager
的状态是否一致,由于 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
的生命周期,经过这段代码咱们就能够对它的生命周期有更加直观的理解。