[toc]
引言
Fragment大家接触的非常多的一个安卓组件,一般我们在使用fragment的时候往往通过下面这种方式创建,那Fragment是如何显示到屏幕上并且回调对应的生命周期呢?
getSupportFragmentManager().beginTransaction()
.add(id, Fragment.instantiate(this, Fragment.class.getName(),
bundle), Fragment.TAG)
.commit();
这个过程可以分为四个步骤。
1、Fragment的创建:Fragment.instantiate(this, Fragment.class.getName()
2、获取SupportFragmentManager:getSupportFragmentManager()
3、开启一个事务并且做出添加操作:beginTransaction().add()
4、执行这次操作:commit()
1、Fragment的创建
/**
* Create a new instance of a Fragment with the given class name. This is
* the same as calling its empty constructor.
*
* @param context The calling context being used to instantiate the fragment.
* This is currently just used to get its ClassLoader.
* @param fname The class name of the fragment to instantiate.
* @param args Bundle of arguments to supply to the fragment, which it
* can retrieve with {@link #getArguments()}. May be null.
* @return Returns a new fragment instance.
* @throws InstantiationException If there is a failure in instantiating
* the given fragment class. This is a runtime exception; it is not
* normally expected to happen.
*/
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
try {
Class<?> clazz = sClassMap.get(fname);
if (clazz == null) {
// Class not found in the cache, see if it's real, and try to add it
clazz = context.getClassLoader().loadClass(fname);
sClassMap.put(fname, clazz);
}
Fragment f = (Fragment) clazz.getConstructor().newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.setArguments(args);
}
return f;
}
}
总结:创建过程先会在缓存中查找是否已加载过这个fragment,如果没有创建过会通过反射,简单的调用了fragment的无参构造方法。
2、getSupportFragmentManager()
//FragmentActivity.java
/**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
*/
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
获取mFragments的supportFragmentManager
final FragmentController mFragments = FragmentController.createController(new HostCallbacks())
这里的mFragments是FragmentActivity的一个成员变量,在FragmentActivity创建的时候就被实例化
谁new了Activity -> Activity的启动流程
public class FragmentController {
private final FragmentHostCallback<?> mHost;
public static FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
private FragmentController(FragmentHostCallback<?> callbacks) {
mHost = callbacks;
}
public FragmentManager getSupportFragmentManager() {
return mHost.getFragmentManagerImpl();
}
}
getSupportFragmentManager返回的实际是mHost的getFragmentManagerImpl()对象。这里的mHost是在Controller创建的时候赋值的,由外界传入的HostCallBack,这个类是FragmentActivity中的一个内部类,所以其中可以直接使用Fragment.this
class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
public HostCallbacks() {
super(FragmentActivity.this /*fragmentActivity*/);
}
}
HostCallBack继承于FragmentHostCallBack,其中持有了Activity,context,handler等对象,可以实现Fragment和Activity的通信,而mHost中返回的FragmentManger实际就是FragmentManagerImpl这个成员变量。
public abstract class FragmentHostCallback<E> extends FragmentContainer {
@Nullable private final Activity mActivity;
@NonNull private final Context mContext;
@NonNull private final Handler mHandler;
private final int mWindowAnimations;
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
}
总结:getSupportFragmentManager()
返回的实际是FragmentManagerImpl这个对象,所有对于fragment的操作也基本在其中实现的。FragmentManagerImpl是非常重要的一个类,我们对于与fragment操作最终都会调用到这里面,后面介绍。
3、 beginTransaction().add()
//FragmentManagerImpl.java
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator{
final FragmentManagerImpl mManager;
public BackStackRecord(FragmentManagerImpl manager) {
mManager = manager;
}
}
这里创建了一个BackStackRecord对象,其中传入的this是FragmentManagerImpl的实例对象。BackStackRecord是操作事务FragmentTransaction的具体实现类。FragmentTransaction里定义了我们对于Fragment的一系列操作,例如add,remove,replace等。而最终我们执行的的add,remove其实都只是在一个事务中的操作,最后的commit实际是由mManger执行。
//BackStackRecord.java
@Override
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
add(int containerViewId, Fragment fragment)
会调用到 doAddOp(containerViewId, fragment, null, OP_ADD)
中。doAddOp顾名思义是在事务中添加一个Op的过程,可以理解为我们的每一个BackStackRecord事务,是由多个Op组成的一个过程。所以类似replace(),remove(),等方法都会添加一个Op,只是不同的Op类型不一样而已。下面具体看看 doAddOp(containerViewId, fragment, null, OP_ADD)
这个方法。
//BackStackRecord.java
private void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
final Class fragmentClass = fragment.getClass();
final int modifiers = fragmentClass.getModifiers();
if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
|| (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
+ " must be a public static class to be properly recreated from"
+ " instance state.");
}
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 (containerViewId == View.NO_ID) {
throw new IllegalArgumentException("Can't add fragment "
+ fragment + " with tag " + tag + " to container view with no id");
}
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
addOp(new Op(opcmd, fragment));
}
这里的步骤也比较简单,一开始判断了Fragment的修饰符是否为public,fragment的tag是否已经存在,指定的占位containerViewId,并把这些信息都保存到Framgment中。最后调用了addOp(new Op(opcmd, fragment))
。
// BackStackRecord.java
ArrayList<Op> mOps = new ArrayList<>();
void addOp(Op op) {
mOps.add(op);
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
}
只是向mOps这里List中添加了一个记录。这里我们发现,对于每一个Op而言,enterAnim、exitAnim、popEnterAnim
、popExitAnim都是通过BackStackRecord的变量赋值的,通过public FragmentTransaction setCustomAnimations(int enter, int exit,int popEnter, int popExit)
设置,这里应该是想保持在一个事务里的动画一致。
总结: beginTransaction开启了一个事务,之后调用add向集合中添加了一个Op,一个事务可以由多个Op组成。
4、commit()
// BackStackRecord.java
@Override
public int commit() {
return commitInternal(false);
}
执行commit()
后,会调用commitInternal(boolean allowStateLoss)
传入false。
// BackStackRecord.java
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
在这个方法中,会通过标志位判断这个commit是否已经执行过。之后判断mAddToBackStack参数,默认情况下为false,当我们调用了
// BackStackRecord.java
@Override
public FragmentTransaction addToBackStack(@Nullable String name) {
if (!mAllowAddToBackStack) {
throw new IllegalStateException(
"This FragmentTransaction is not allowed to be added to the back stack.");
}
mAddToBackStack = true;
mName = name;
return this;
}
方法之后,这个标志位置为ture,可以猜想 mManager.allocBackStackIndex(this)
这块儿应该处理了返回按钮回退事务的逻辑。无论如何最终都会走到 mManager.enqueueAction(this, allowStateLoss)
里。
//FragmentManagerImpl.java
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
if (allowStateLoss) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
//在这个集合中添加了刚才的BackStackRecord
mPendingActions.add(action);
scheduleCommit();
}
}
private void checkStateLoss() {
if (isStateSaved()) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException(
"Can not perform this action inside of " + mNoTransactionsBecause);
}
}
这个方法里,如果allowStateLoss
传入false的话,会进行一个状态的检查。这里可能会抛出这样一个异常Can not perform this action after onSaveInstanceState
。可能是因为用户的某个操作引起了onSaveInstanceState()
之后调用了commit()
,FragmentManger如果在没有保存当前状态的情况下就会在这里抛出了异常,一般commitAllowingStateLoss()
调用这个方法避免这种异常,但不确定在某些场景下会不会出现问题。
之后,创建了mPendingActions
集合,向其中添加了了一个action,这个action是OpGenerator
接口,BackStackRecord实现了这个接口。随后调用了scheduleCommit()
//FragmentManagerImpl.java
/**
* Schedules the execution when one hasn't been scheduled already. This should happen
* the first time {@link #enqueueAction(OpGenerator, boolean)} is called or when
* a postponed transaction has been started with
* {@link Fragment#startPostponedEnterTransition()}
*/
@SuppressWarnings("WeakerAccess") /* synthetic access */
void scheduleCommit() {
synchronized (this) {
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
//先进行一次cancel操作,确保只有一个Runnable在执行。
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
最终走到mHost.getHandler.post(mExecCommit)
这里的handler,就是之前提到HostCallBack中的handler,由FragmentActivity提供。这个Runnable通过这个handler运行在主线程中。
这里为什么一定要让这个过程在主线程中运行?
//FragmentManagerImpl.java
/**
* Only call from main thread!
*/
public boolean execPendingActions() {
//执行前的状态检查
ensureExecReady(true);
boolean didSomething = false;
// generateOpsForPendingActions会循环判断当前是否还有任务
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
doPendingDeferredStart();
burpActive();
return didSomething;
}
在主线程执行的这个方法首先调用了ensureExecReady(true)
这个方法中做了一些状态判断,例如是否在主线程,当前Activity是否已经被销毁等。随后走到generateOpsForPendingActions(mTmpRecords, mTmpIsPop)
//FragmentManagerImpl.java
/**
* Adds all records in the pending actions to records and whether they are add or pop
* operations to isPop. After executing, the pending actions will be empty.
*
* @param records All pending actions will generate BackStackRecords added to this.
* This contains the transactions, in order, to execute.
* @param isPop All pending actions will generate booleans to add to this. This contains
* an entry for each entry in records to indicate whether or not it is a
* pop action.
*/
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isPop) {
boolean didSomething = false;
synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
return false;
}
final int numActions = mPendingActions.size();
for (int i = 0; i < numActions; i++) {
//这里的mPendingActions就是一开始enqueueAction(OpGenerator action, boolean allowStateLoss) 方法中传入的action,即BackStackRecord对象
didSomething |= mPendingActions.get(i).generateOps(records, isPop);
}
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
return didSomething;
}
// BackStackRecord.java
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
records.add(this);
isRecordPop.add(false);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
return true;
}
结合着generateOpsForPendingActions
的注释,这段代码是比较容易搞懂的。首先我们在BackStackRecord.commit()
的时候将自己作为一个action添加到了mPendingActions这个集合中,在这里对每一个action接口调用generateOps(records, isPop)
传入第一个集合mTmpRecords表示需要执行事务,这里直接add了BackStack对象自身。第二个集合表示这个事务是否是pop操作,在BackStackRecord中直接add了一个false,整个方法返回了trure。
回到execPendingActions()
方法,执行removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop)
方法
//FragmentManagerImpl.java
//从注释来看,这个方法可以优化事务的执行:
//例如,一个事务执行了add操作,然后另一个事务执行pop,将被优化以删除不必要的操作。
//同样地,同时执行的两个提交的事务将被优化以删除冗余的操作以及同时执行的两个pop操作。
//猜想应该是其中的循环流程处理了这样的操作,后续学习一下这块儿指令重排的设计。
private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop) {
// Force start of any postponed transactions that interact with scheduled transactions:
executePostponedTransaction(records, isRecordPop);
final int numRecords = records.size();
int startIndex = 0;
for (int recordNum = 0; recordNum < numRecords; recordNum++) {
final boolean canReorder = records.get(recordNum).mReorderingAllowed;
if (!canReorder) {
// execute all previous transactions
if (startIndex != recordNum) {
executeOpsTogether(records, isRecordPop, startIndex, recordNum);
}
// execute all pop operations that don't allow reordering together or
// one add operation
int reorderingEnd = recordNum + 1;
if (isRecordPop.get(recordNum)) {
while (reorderingEnd < numRecords
&& isRecordPop.get(reorderingEnd)
&& !records.get(reorderingEnd).mReorderingAllowed) {
reorderingEnd++;
}
}
executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
startIndex = reorderingEnd;
recordNum = reorderingEnd - 1;
}
}
if (startIndex != numRecords) {
executeOpsTogether(records, isRecordPop, startIndex, numRecords);
}
}
除去循环进行重排的地方,最终都会调用到executeOpsTogether(records, isRecordPop, startIndex, recordNum)
//FragmentManagerImpl.java
private void executeOpsTogether(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
····
executeOps(records, isRecordPop, startIndex, endIndex);
····
}
//FragmentManagerImpl.java
private static void executeOps(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
for (int i = startIndex; i < endIndex; i++) {
final BackStackRecord record = records.get(i);
final boolean isPop = isRecordPop.get(i);
if (isPop) {
record.bumpBackStackNesting(-1);
// Only execute the add operations at the end of
// all transactions.
boolean moveToState = i == (endIndex - 1);
record.executePopOps(moveToState);
} else {
record.bumpBackStackNesting(1);
//执行操作
record.executeOps();
}
}
}
// BackStackRecord.java
void executeOps() {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.fragment;
if (f != null) {
f.setNextTransition(mTransition, mTransitionStyle);
}
switch (op.cmd) {
case OP_ADD:
f.setNextAnim(op.enterAnim);
//添加到mActive集合中
mManager.addFragment(f, false);
break;
}
if (!mReorderingAllowed && op.cmd != OP_ADD && f != null) {
mManager.moveFragmentToExpectedState(f);
}
}
if (!mReorderingAllowed) {
// Added fragments are added at the end to comply with prior behavior.
//同步状态 那Manger的这个状态由谁修改-> FragmentActivity
mManager.moveToState(mManager.mCurState, true);
}
}
根据调用轨迹最终走到 executeOps()
里,以add操作为例。将生成的这个Fragment添加到FragmentManger中的mActivie集合中。
最后调用Manager的moveToState,这里传入Manager的状态值来自于FragmentActivity的生命周期的回调
图片来自网络 并非十分精确
@SuppressWarnings("ReferenceEquality")
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
······
switch (f.mState) {
case Fragment.INITIALIZING:
//预分发fragment attach的回调
//调用fragment的onAttach
//预分发fragment onCreate的回调
//调用fragment的onCreate
//将fragment移动到下一个状态
case Fragment.CREATED:
//查找Fragment添加位置的Id
//调用fragment的onCreateView
//将fragment创建出来的对象添加到container的位置
//这个container是一个ViewGroup对象
//调用fragment的onViewCreated
······
}
} else if (f.mState > newState) {
//这里处理了fragment的生命周期比Manger的周期提前的情况,让fragment和activiy保持同步
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
f.performPause();
dispatchOnFragmentPaused(f, false);
}
// fall through
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
f.performStop();
dispatchOnFragmentStopped(f, false);
}
······
}
}
moveToState就是Fragment中最核心的方法,他的作用是同步Fragment和Activity的生命周期一致。这里就会出现两种情况1、fragment的生命周期比activity滞后;2、fragment的生命周期比activity超前。一般我们在创建fragment的时候都是情况1。
在情况1中,通过将framgent 与activity的生命周期作比较进行不同的操作
例如,当fragment的生命周期位于INITIALIZING
的时候
if (newState > Fragment.INITIALIZING) {
//预分发fragment attach的回调
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.mCalled = false;
//调用fragment的onAttach
f.onAttach(mHost.getContext());
dispatchOnFragmentAttached(f, mHost.getContext(), false);
if (!f.mIsCreated) {
//预分发fragment onCreate的回调
dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
//调用fragment的onCreate
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
} else {
f.restoreChildFragmentState(f.mSavedFragmentState);
//将fragment移动到下一个状态
f.mState = Fragment.CREATED;
}
}
首先分发了fragment attach事件,之后回调执行fragment的onAttach以及Create方法最后将fragment的状态移动到Created,并且修改标志位,保证这个流程不会重复执行,所以Activity处于INITIALIZING
状态的时候,其实对应的是fragment的onAttach和onCreated。注意这里的swtich 每一个case后面都没有break,所以执行完上面的逻辑后走到第二个判断。当fragment的生命周期位于CREATED
的时候,如果这个时候activity的生命周期还比fragment超前,则走下面的流程这个。
if (newState > Fragment.CREATED) {
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
//查找Fragment添加位置的Id
container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
}
f.mContainer = container;
//调用fragment的onCreateView
f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
//将fragment创建出来的对象添加到container的位置
//这个container是一个ViewGroup对象
container.addView(f.mView);
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
//调用fragment的onViewCreated
f.onViewCreated(f.mView, f.mSavedFragmentState);
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
false);
} else {
f.mInnerView = null;
}
}
//调用fragment的onActivityCreated
f.performActivityCreated(f.mSavedFragmentState);
//分发事件
dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
}
这里是fragment显示的关键代码,先根据我们传入的id查找这个占位的View,之后调用fragment的onCreateView
,一般我们在使用的时候都会在这个方法中返回创建的VIew。之后将这个view添加到container中,进行view的展示,最后回调对应的生命周期完成。
总结:
1、commit()
首先会进行一些状态的判断,这里可能会抛出 IllegalStateException("Can not perform this action after onSaveInstanceState")
异常。一般commitAllowingStateLoss()
调用这个方法避免这种异常,但不确定在某些场景下会不会出现问题。
2、之后将这个事务添加到队列中,通过activity的handler将具体的执行运行到主线程中
3、先对事务集合进行优化,之后遍历执行每一个事务
4、moveToState
中将Activity的状态与fragment的状态进行同步,所有fragment的生命周期回调都是在这个方法中被调用的。在CREATED
状态下,调用fragment的onCreateView生成显示的视图,并且添加到指定id的位置上进行展示。
全流程总结:
1、framgnet的创建:创建过程先会在缓存中查找是否已加载过这个fragment,如果没有创建过会通过反射,简单的调用了fragment的无参构造方法。
2、getSupportFragmentManager():getSupportFragmentManager()
返回的实际是FragmentManagerImpl这个对象,所有对于fragment的操作也基本在其中实现的。FragmentManagerImpl是非常重要的一个类,我们对于与fragment操作最终都会调用到这里面。
3、beginTransaction().add(): beginTransaction开启了一个事务,之后调用add向集合中添加了一个Op,一个事务可以由多个Op组成。
4、commit():commit()
首先会进行一些状态的判断,这里可能会抛出 IllegalStateException("Can not perform this action after onSaveInstanceState")
异常。一般commitAllowingStateLoss()
调用这个方法避免这种异常,但不确定在某些场景下会不会出现问题。之后将这个事务添加到队列中,通过activity的handler将具体的执行运行到主线程中。执行过程先对事务集合进行优化,之后遍历执行每一个事务。moveToState中将Activity的状态与fragment的状态进行同步,所有fragment的生命周期回调都是在这个方法中被调用的。在CREATED
状态下,调用fragment的onCreateView生成显示的视图,并且添加到指定id的位置上进行展示。
遗留问题
1、谁new了Activity -> Activity的启动流程
2、为什么commit一定要在主线程中执行
3、事务的指令优化是如何处理的