Fragment生命周期
如何理解Activity的onCreate执行期间Fragment才从onAttach开始?这个过程是如何进行的?
这个过程的触发方法实际上是Activity的onCreate方法中的setContentView,更准确的说是setContentView触发的LayoutInflater.inflate去解析布局,而Activity自身也是LayoutInflater.Factory的实现类,其内部的onCreateView方法专门负责XML布局中的fragment标签元素的解析,会触发Fragment反射实例化;而之后再FragmentActivity的onCreate方法中对实例化的Fragment调用moveToState进行Fragment状态迁移,从而触发Fragment的生命周期。
Fragmenet与View异同
Fragment更像是一个复杂的ViewGroup,复杂有两点:
- 有自己的生命周期;
- 有返回堆栈。
但是Fragment也有自己独特的地方,即哪里用哪里搬、啥时候用啥时候搬;Fragment在使用时会伴随着hide、show、remove、add、replace等事务,从而实现在一个Activity上展现出跳转不同页面的效果,但是实际上只是这一页面上某个区域内部的切换罢了。这就是Fragment不同于ViewGroup的地方 — 频繁的Fragment对象的切换带来的频繁的内容切换,因为ViewGroup通常是固定的,不会被频繁切换。
这也就带来了要对Fragment进行复用的需要,因此也就带来了Fragment事务、回退栈的需求。
Fragment与Activity异同
Fragment之所以给人一种像Activity的感觉无非是其具有相似的生命周期,但这也是区别之处:
-
Activity的生命周期由系统控制;
-
Fragment的生命周期伴随着Activity的生命周期方法onXXX的回调,FragmentActivity内部执行mFragmentManager的dispatchXXX方法使得Fragment的状态发生转移,从而发生Fragment的生命周期调用;可以说,Fragment的生命周期是一种应用层面的,被Activity所控制。(Fragment事务的思想正是主动改变Fragment的状态、使得Fragment的状态暂时脱离宿主Activity而存在)。
一、Activity与FragmentManager
Activity中获取FragmentManager并不容易(以下内容都是androidx包下的Fragment相关机制):
// FragmentActivity.java
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
public FragmentManager getFragmentManager() {
return mFragments.getFragmentManager();
}
复制代码
可见,Activity中获取FragmentManager并不是一帆风顺的,而是交给了FragmentController
对象去获取,而在Activity中FragmentController对象被原地初始化了,接下来就看看初始化的工作:
// FragmentController.java
private final FragmentHostCallback<?> mHost;
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
// 实际上就是调用构造器进行初始化,只不过构造器使用private修饰,只能够使用这种静态方式进行
return new FragmentController(callbacks);
}
private FragmentController(FragmentHostCallback<?> callbacks) {
mHost = callbacks;
}
public FragmentManager getFragmentManager() {
// 而其将获取FragmentManager的工作,交给了mHost属性去做,该属性在构造器中被传入
return mHost.getFragmentManagerImpl();
}
复制代码
可以看到,最终获取FragmentManager的调用时mHost进行的,而具体的方法实现就是一开始传入的HostCallbacks的父类 — FragmentHostCallback
:
//FragmentHostCallback.java
public abstract class FragmentHostCallback<E> extends FragmentContainer {
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
FragmentManagerImpl getFragmentManagerImpl() {
return mFragmentManager;
}
}
复制代码
很清晰,就是初始化的FragmentManagerImpl
对象。
备注:实际上浏览==FragmentController==这个类的方法实现可以发现,该类中的所有方法的实现都是mHost.mFragmentManager.XXX,因此,我们可以将FragmentController全当为FragmentManagerImpl来看待!!
二、核心类
核心属性展示:
// FragmentManager.java(androidx)
public abstract class FragmentManager {
private final ArrayList<OpGenerator> mPendingActions = new ArrayList<>(); // 表示是入栈操作还是出栈操作
ArrayList<BackStackRecord> mBackStack; // 回退栈,元素为每次事务commit的BackStackRecord对象
private final FragmentStore mFragmentStore = new FragmentStore(); // 顾名思义,FragmentManager中管理已经add过的Fragment
FragmentHostCallback<?> mHost;
FragmentContainer mContainer; // FragmentHostCallback为FragmentContainer的实现类
// 三个暂存list,代码执行过程中会使用到,不过执行完就会清除
// Temporary vars for removing redundant operations in BackStackRecords:
private ArrayList<BackStackRecord> mTmpRecords;
private ArrayList<Boolean> mTmpIsPop;
private ArrayList<Fragment> mTmpAddedFragments;
int mCurState = Fragment.INITIALIZING; // FragmentManager当前的状态!!
}
// FragmentStore.java
class FragmentStore {
private final ArrayList<Fragment> mAdded = new ArrayList<>(); // 已经add过的Fragment
private final HashMap<String, FragmentStateManager> mActive = new HashMap<>();
}
复制代码
三、静态Fragment的加载
静态Fragment是通过在xml布局中使用fragment标签定义的Fragment,其加载过程被定义在Activity
的onCreateView方法中,Activity作为LayoutInflater.Factory2
接口的实现类,将该方法的实现委托给了mFragments属性执行,通过上文的分析,我们知道在Activity的子类FragmentActivity中,mFragments具体实现类为FragmentController
,因此,解析XML中Fragment标签的任务就交给了FragmentController:
//FragmentController.java
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
return mHost.mFragmentManager.getLayoutInflaterFactory()
.onCreateView(parent, name, context, attrs);
}
复制代码
同样,这里的mFragmentManager的具体实现类是androidx包下的FragmentManagerImpl
,那么加载过程就来到了FragmentManager中:
// FragmentManager.java
private final FragmentLayoutInflaterFactory mLayoutInflaterFactory =
new FragmentLayoutInflaterFactory(this);
// FragmentLayoutInflaterFactory.java
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
// 只管解析Fragment
if (!"fragment".equals(name)) {
return null;
}
// 获取到Fragment的全限定类名
String fname = attrs.getAttributeValue(null, "class");
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Fragment);
if (fname == null) {
// 获取到Fragment的全限定类名
fname = a.getString(R.styleable.Fragment_android_name);
}
// id
int id = a.getResourceId(R.styleable.Fragment_android_id, View.NO_ID);
// tag
String tag = a.getString(R.styleable.Fragment_android_tag);
a.recycle();
int containerId = parent != null ? parent.getId() : 0;
// 优先尝试复用Fragment
// 首先通过mFragmentManager的findFragmentById
// 其次通过mFragmentManager的findFragmentByTag
// 最后通过mFragmentManager使用containerId尝试find
Fragment fragment = id != View.NO_ID ? mFragmentManager.findFragmentById(id) : null;
if (fragment == null && tag != null) {
fragment = mFragmentManager.findFragmentByTag(tag);
}
if (fragment == null && containerId != View.NO_ID) {
fragment = mFragmentManager.findFragmentById(containerId);
}
// 如果没能复用,那么就instantiate初始化Fragment
if (fragment == null) {
fragment = mFragmentManager.getFragmentFactory().instantiate(
context.getClassLoader(), fname);
// 这个标签说明该Fragment对象是从xml文件中加载的Fragment
fragment.mFromLayout = true;
fragment.mFragmentId = id != 0 ? id : containerId;
fragment.mContainerId = containerId;
fragment.mTag = tag;
// 表示被添加到了Layout中
fragment.mInLayout = true;
fragment.mFragmentManager = mFragmentManager;
fragment.mHost = mFragmentManager.mHost;
fragment.onInflate(mFragmentManager.mHost.getContext(), attrs,
fragment.mSavedFragmentState);
// 这里实际上是添加到了mFragmentManager的mFragmentStore中
mFragmentManager.addFragment(fragment);
// 核心!!进行状态转移!!
mFragmentManager.moveToState(fragment);
}
// 再次执行moveToState,状态迁移至CREATED
if (mFragmentManager.mCurState < Fragment.CREATED && fragment.mFromLayout) {
mFragmentManager.moveToState(fragment, Fragment.CREATED);
} else {
mFragmentManager.moveToState(fragment);
}
if (id != 0) {
fragment.mView.setId(id);
}
if (fragment.mView.getTag() == null) {
fragment.mView.setTag(tag);
}
return fragment.mView;
}
复制代码
到这里,我们可以小结一下xml布局中的fragment标签的解析过程:
- 复用阶段:FragmentManager尝试从FragmentStore中复用已有的Fragment对象,优先级如下
- 通过布局中的id属性查找;
- 通过布局中的tag属性查找;
- 通过containerId查找。
- 新建阶段:如果是第一次解析该Fragment,那么FragmentManager将使用FragmentFactory来执行对该Fragment的初始化,具体实现是利用反射调用无参构造器,这也就证实了,自定义Fragment时为何一定要提供一个无参构造器了;在创建出Fragment对象之后,调用mFragmentStrore的add方法将该Fragment保存了起来;
- 状态迁移阶段:在初始化Fragment时,首先执行一次moveToState,需要将Fragment迁移至FragmentManager默认初始状态Fragment.INITIALIZING;之后,再次执行moveToState,将Fragment迁移至CREATED状态。
另外,值得注意的是,我们知道LayoutInflater解析xml文件返回的都是View,而Fragment本身并不是View的子类;那么,FragmentLayoutInflaterFactory
工作在LayoutInflater的体系中,就必须满足要求,因此可以看出上述的onCreateView返回的是fragment的mView属性,因此最终被ViewGroup添加的正是这个mView。从==这里也可以看出Fragment与View的区别:Fragment不是View,他因为Activity的LayoutInflater.Factory2的原因,在layout文件中,单独被Activity拦截解析fragment标签;而LayoutInflater.Factory2工作在LayoutInflater解析文件的体系中,必须满足LayoutInflater的要求,所以其功能实现类FragmentLayoutInflaterFactory
在onCreateView中,最终返回的是Fragment的mView属性,利用这种机制,来完成对Fragment的静态使用,使得Fragment能够像一个View一样定义在layout文件中,但是Fragment本身并不是View体系中的一员。同时,Fragment也作为这个mView的持有者和管理者,赋予了mView相对独立的生命周期,使得mView可以暂时detach、attach到Activity中。这是其他普通的ViewGroup或者View所不能做到的。==
Fragment复用 — FragmentStore
上面的过程中,涉及到了Fragment的复用过程,在FragmentManager中,这一过程拆解出来,交给了FragmentStore去实现:
// FragmentManager.java
public Fragment findFragmentById(@IdRes int id) {
return mFragmentStore.findFragmentById(id);
}
public Fragment findFragmentByTag(@Nullable String tag) {
return mFragmentStore.findFragmentByTag(tag);
}
Fragment findFragmentByWho(@NonNull String who) {
return mFragmentStore.findFragmentByWho(who);
}
复制代码
可见,都是交给了FragmentStore去完成:
// FragmentStore.java
private final ArrayList<Fragment> mAdded = new ArrayList<>(); // 已将添加过的Fragment
private final HashMap<String, FragmentStateManager> mActive = new HashMap<>(); // 暂时意义不明
Fragment findFragmentById(@IdRes int id) {
// First look through added fragments.
for (int i = mAdded.size() - 1; i >= 0; i--) {
Fragment f = mAdded.get(i);
if (f != null && f.mFragmentId == id) {
return f;
}
}
// Now for any known fragment.
for (FragmentStateManager fragmentStateManager : mActive.values()) {
if (fragmentStateManager != null) {
Fragment f = fragmentStateManager.getFragment();
if (f.mFragmentId == id) {
return f;
}
}
}
return null;
}
复制代码
这里以Byid为例,发现就是遍历对比,没什么特殊的方法。记得,上面在解析完xml中的fragment对象后,将其添加到了FragmentStore中,也就是添加到了上面的mAdded属性中。
Fragment初始化 — FragmentFactory
在FragmentManager中有一个mFragmentFactory默认为null,用户可以调用FragmentManager的setFragmentFactory来指定一个FragmentFactory对象,同时还有一个mHostFragmentFactory,而FragmentManager的getFragmentFactory()方法实现如下:
// FragmentManager.java
private FragmentFactory mFragmentFactory = null;
private FragmentFactory mHostFragmentFactory = new FragmentFactory() {
public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
return mHost.instantiate(mHost.getContext(), className, null);
}
};
public FragmentFactory getFragmentFactory() {
if (mFragmentFactory != null) {
return mFragmentFactory;
}
if (mParent != null) {
return mParent.mFragmentManager.getFragmentFactory();
}
return mHostFragmentFactory;
}
复制代码
可见,在没有调用过setFragmentFactory的情况下,最终返回的依然是mHostFragmentFactory,而其内部初始化Fragment使用的是FragmentHostCallback — mHost的instantiate方法,只不过该方法的实现,位于其父类FragmentContainer中:
// FragmentContainer.java
public Fragment instantiate(@NonNull Context context, @NonNull String className,
@Nullable Bundle arguments) {
// 使用Fragment的静态方法进行初始化
return Fragment.instantiate(context, className, arguments);
}
// Fragment.java
public static Fragment instantiate(@NonNull Context context, @NonNull String fname,
@Nullable Bundle args) {
try {
Class<? extends Fragment> clazz = FragmentFactory.loadFragmentClass(
context.getClassLoader(), fname);
// 经典调用无参构造器
Fragment f = clazz.getConstructor().newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.setArguments(args);
}
return f;
}
}
复制代码
又是经典的反射使用,这也就是在自定义Fragment的时候必须要提供一个无参构造器的原因!!
Fragment状态转移 — moveToState
而Fragment中mState属性默认是INITIALIZING,同时,Fragment还有一个mMaxState属性,表示Fragment最高能够达到的状态,注意,这个mMaxState为Lifecycle的状态,只不过在Fragment中为这几种状态提供了对应的值,因此我们可以将其当做为Fragment状态,默认为Lifecycle.State.RESUMED对标为Fragment.RESUMED。
在FragmentManager中对Fragment进行管理的、实现状态迁移的机制有两种,即对应了两种回调:moveToState(Fragment),moveToState(Fragment, int);后者的机制是将目标Fragment迁移至指定状态,而前者内部回调的后者,只不过第二个参数设置的是Fragment当前的状态mCurState。
除此之外,FragmentManager也有自己的状态,即上面展示的mCurState;同时,FragmentManager也提供了一个moveToState(int, boolean)方法来为自己提供状态转移支持。同时,FragmentManager的mCurState的更改方式,只有通过moveToState(int, boolean)这一种方法。
四、静态使用Fragment时,Activity声明周期对Fragment声明周期的影响过程
我们都知道,Activity通过FragmentManager来管理Fragment,并且Fragment的声明周期受Activity的声明周期支配,接下来就探究一下Activity的声明周期回调时,如何影响Fragment的生命周期的。
注意!!一下代码分析的是androidx包下的Fragment与Activity启动机制,除此之外还有一个android包下的Fragment,二者在调用上几乎一模一样,但就是不同的东西,切勿混淆!!
Activity — onCreate
我们先来看看FragmentActivity中对该方法的实现:
// FragmentActivity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
super.onCreate(savedInstanceState);
mFragments.dispatchCreate();
}
复制代码
通过上文的介绍,我们知道,这里的mFragments属性是一个FragmentController实例,只不过其方法都是委托给FragmentManager去实现的,因此,这里实际上就是调用了FragmentManager的dispatchCreate()
方法:
// FragmentManager.java
void dispatchCreate() {
mStateSaved = false;
mStopped = false;
dispatchStateChange(Fragment.CREATED);
}
private void dispatchStateChange(int nextState) {
try {
mExecutingActions = true;
mFragmentStore.dispatchStateChange(nextState);
// 进行状态迁移,注意,由于是从Activity传递过来的,所以代表的是迁移FragmentManager的状态
// 因此这里调用的是moveToState(int, boolean)这个方法
moveToState(nextState, false);
} finally {
mExecutingActions = false;
}
// 涉及到FragmentManager事务,先不管
execPendingActions(true);
}
复制代码
关于该方法的实现,以及调用过程,上面展示的很明白;同时,此时我们先只关心moveToState方法的调用。注意,由于是从Activity传递过来的,所以代表的是迁移FragmentManager的状态;因此,这里调用的是moveToState(int, boolean)这个方法;同时,第二个参数传递的是false。
// FragmentManager.java
void moveToState(int newState, boolean always) {
....
mCurState = newState;
....
}
复制代码
上述源码是本次执行时真正起作用的代码,之所以这么特殊,最核心的一点是:==此时Activity属于onCreate方法刚被调用,setContentView还没有被执行,也就是说layout文件中的Fragment还没有触发解析,因此,此时FragmentManager的mFragmentStore中还没有add任何Fragment。此时,该方的作用只有一个:将FragmentManager的mCurState状态保持与Activity同步,同步为CREATED==。
那么,这会带来什么影响呢?回到Activity的流程中来,setContentView触发FragmentLayoutInflaterFactory解析layout文件中的Fragment标签,实现中有如下部分:
// FragmentLayoutInflaterFactory.java
// 如果没能复用,那么就instantiate初始化Fragment
if (fragment == null) {
fragment = mFragmentManager.getFragmentFactory().instantiate(
context.getClassLoader(), fname);
// 这个标签说明该Fragment对象是从xml文件中加载的Fragment
fragment.mFromLayout = true;
// 表示被添加到了Layout中
fragment.mInLayout = true;
// 这里实际上是添加到了mFragmentManager的mFragmentStore中
mFragmentManager.addFragment(fragment);
// 核心!!进行状态转移!!
mFragmentManager.moveToState(fragment);
}
复制代码
对本部分来说,==最重要的就是两步:mFragmentManager.addFragment(fragment)与mFragmentManager.moveToState(fragment)。前者将fragment对象添加到mFragmentStore中,这样,FragmentManager才获得了需要管理的Fragment;最最最重要的是后者,对新建的Fragment执行状态迁移!!同时,由于是对Fragment执行状态迁移,所以这里调用的是moveToState(Fragment)这个签名的方法。==
// FragmentManager.java
void moveToState(@NonNull Fragment f) {
// 注意刚提到的,此时FragmentManager的mCurState为CREATED!!!
moveToState(f, mCurState);
}
void moveToState(@NonNull Fragment f, int newState) {
// 由于是对该Fragment第一次执行moveToState,所以fragmentStateManager为null
// 于是需要进入if语句新建一个
FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
if (fragmentStateManager == null) {
fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher, f);
// 这里为内部属性初始化为了CREATED
fragmentStateManager.setFragmentManagerState(Fragment.CREATED);
}
// 当前情况下,就为CREATED
newState = Math.min(newState, fragmentStateManager.computeMaxState());
if (f.mState <= newState) {
switch (f.mState) {
// 刚刚从xml解析出来fragment,第一次执行moveToState
// 显然,此时Fragment的mState为INITIALIZING
case Fragment.INITIALIZING:
if (newState > Fragment.INITIALIZING) {
...
// 执行完毕后,Fragment的状态变为ATTACHED,因此匹配到下一个case
fragmentStateManager.attach(mHost, this, mParent);
}
case Fragment.ATTACHED:
if (newState > Fragment.ATTACHED) {
// 执行完毕后,Fragment的状态变为了CREATED,因此匹配到下一个case
fragmentStateManager.create();
}
case Fragment.CREATED:
// newState为CREATED,满足条件,进入if语句
if (newState > Fragment.INITIALIZING) {
// 执行Fragment的onCreateView以及onViewCreated声明周期回调
// 由于这两个声明周期回调没有定义对应的状态
// 所以Fragment的mState依然是CREATED
fragmentStateManager.ensureInflatedView();
}
// 由于当前Activity状态为CREATED -- FragmentManager也是
// Activity的onCreate流程执行moveToState止步于此
if (newState > Fragment.CREATED) {
fragmentStateManager.createView(mContainer);
fragmentStateManager.activityCreated();
fragmentStateManager.restoreViewState();
}
case Fragment.ACTIVITY_CREATED:
}
} ...
}
复制代码
通过上述代码注释,可以看出Activity的生命周期回调是如何影响Fragment生命周期回调的:
- FragmentManager的生命周期状态与Activity同步:在Activity的onCreate中通过调用mFragments的dispatchCreate方法实现Activity生命周期状态的分发,FragmentManager接收到信号后将自己的状态mCurState与Activity同步;很容易理解,FragmentManager本身就是Activity用来管理Fragment的工具类,其状态自然要依附于Parent;
- Fragment生命周期受限于Activity(FragmentManager)的声明周期:具体表现为,moveToState(Fragment, int)方法实现中,fragmentStateManager执行不同方法进行Fragment的生命周期方法回调实现Fragment状态转移的时候,都要满足newState>f.mState的条件 — Fragment当前状态小于Activity(FragmentManager)的状态,即Fragment转移后的状态小于等于Activity的当前状态,通俗一点说就是:Fragment能够进行状态转移的前提是,状态转移后Fragment的状态不能超前于Activity(FragmentManager)。
至此,Activity的onCreate阶段状态转移过程就看完了,通过上面的代码我们知道了,在Activity的onCreate阶段,Fragment依次执行了onAttach、onCreate、onCreateView、onViewCreated四个生命周期回调。
根据上面的讲解,我们可以得到如下调用流程示意:
Activity.onCreate -- begin
Fragment.onAttach
Fragment.onCreate
Fragment.onCreateView
Fragment.onViewCreated
Activity.onCreate -- end
复制代码
此时的状态:
- Activity(FragmentManager):CREATED;
- Fragment:CREATED。
那么后续的生命周期调用该如何继续呢?
Activity — onStart
同样,我们也来看看onStart的代码实现:
// FragmentActivity.java
@Override
protected void onStart() {
super.onStart();
// 贴心的检查了一下
if (!mCreated) {
mCreated = true;
mFragments.dispatchActivityCreated();
}
..
// 熟悉的方法调用,只不过这次分发的是start
mFragments.dispatchStart();
}
复制代码
话不多说,我们知道执行的结果就是调用了FragmentManager的moveToState(int, boolean):
// FragmentManager.java
void dispatchStart() {
mStateSaved = false;
mStopped = false;
dispatchStateChange(Fragment.STARTED);
}
private void dispatchStateChange(int nextState) {
try {
mExecutingActions = true;
mFragmentStore.dispatchStateChange(nextState);
moveToState(nextState, false);
} ...
}
复制代码
熟悉的配方,熟悉的味道。但是虽然调用方法一致,但是运行起来确差多了,因为在onCreate时,Fragment还没有被解析出来,也没有被add进mFragmentStore中,因此moveToState方法只是更改了FragmentManager的mCurState变量;但是此时,Fragment已经被加进来了,我们看看此时moveToState(int, boolean)方法执行的流程:
// FragmentManager.java
void moveToState(int newState, boolean always) {
// 同步当前的生命周期与Activity一致
mCurState = newState;
// 由于Fragment已经被加进来了,所以会对其执行if内部的方法,进行状态迁移
for (Fragment f : mFragmentStore.getFragments()) {
moveFragmentToExpectedState(f);
}
...
}
复制代码
首先,必须要做的是将当前FragmentManager的状态与Activity进行同步;由于解析出的Fragment对象已经加入到了mFragmentStore中,所以会对该Fragment执行moveFragmentToExceptedState方法,顾名思义,该方法最终一定会执行moveToState(Fragment, int)实现Fragment的状态转移。
// FragmentManager.java
void moveFragmentToExpectedState(@NonNull Fragment f) {
// 执行状态转移
moveToState(f);
}
复制代码
那么此时执行状态转移,代码执行过程是如何呢?
// FragmentManager.java
void moveToState(@NonNull Fragment f, int newState) {
// 此时获取到的便不再是null了
FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
// 结果是STARTED
newState = Math.min(newState, fragmentStateManager.computeMaxState());
if (f.mState <= newState) {
switch (f.mState) {
...
case Fragment.CREATED:
// 上次moveToState就止步于此
// 由于此时newState变为了STARTED,满足条件,因此Fragmet可以继续迁移状态了
if (newState > Fragment.CREATED) {
// 对于静态使用Fragment,这个方法没有做任何事,可以忽略
fragmentStateManager.createView(mContainer);
// 执行完毕后,Fragment的状态迁移为了ACTIVITY_CREATED,因此匹配到下一个case
fragmentStateManager.activityCreated();
fragmentStateManager.restoreViewState();
}
case Fragment.ACTIVITY_CREATED:
// newState为STARTED,满足条件,if语句执行
if (newState > Fragment.ACTIVITY_CREATED) {
// 方法执行完毕后,Fragment的状态迁移为了STARTED,因此匹配到下一个case
fragmentStateManager.start();
}
case Fragment.STARTED:
// 显然,newState不满足该条件,止步于此
if (newState > Fragment.STARTED) {
fragmentStateManager.resume();
}
}
}
...
}
复制代码
实际上有了onCreate阶段的讲解,这一次的moveToState(Fragment, int)过程就轻松多了。与上一次相比,Activity的生命周期变为了STARTED,那么Fragment的生命周期也可以迁移到这个上限STARTED。而onCeate阶段结束时,Fragment的状态为CREATED(onCreateView和onViewCreated没有定义对应的状态),在Fragment的生命周期中,CRAETED与STARTED中间还有一个ACTIVITY_CREATED,因此,本次moveToState(Fragment, int)就是使得Fragment完整这两步状态的迁移。
至此,Activity的onStart阶段状态转移过程就看完了,通过上面的代码我们知道了,在Activity的onStart阶段,Fragment依次执行了onActivityCreated、onStart两个生命周期回调。
根据上面的讲解,我们可以得到如下调用流程示意:
Activity.onCreate -- begin
Fragment.onAttach
Fragment.onCreate
Fragment.onCreateView
Fragment.onViewCreated
Activity.onCreate -- end
Activity.onStart -- begin
Fragment.onActivityCreated
Fragment.onStart
Activity.onStart -- end
复制代码
此时的状态:
- Activity(FragmentManager):STARTED;
- Fragment:STARTED。
那么后续的生命周期调用该如何继续呢?
Activity — onResume
同样,onResume的方法传递过程稍微复杂一点,其入口是Activity的performResume:
// Activity.java
final void performResume(boolean followedByPause, String reason) {
onPostResume();
}
// FragmentActivity.java
protected void onPostResume() {
super.onPostResume();
onResumeFragments();
}
protected void onResumeFragments() {
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
mFragments.dispatchResume();
}
复制代码
实际上,后面的过程就和onStart时一模一样了,这里就直接贴出moveToState的代码了:
// FragmentManager.java
// FragmentManager.java
void moveToState(@NonNull Fragment f, int newState) {
// 此时获取到的便不再是null了
FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
// 结果是RESUMED
newState = Math.min(newState, fragmentStateManager.computeMaxState());
if (f.mState <= newState) {
switch (f.mState) {
...
case Fragment.STARTED:
// 此时,newState满足该条件,不载止步于此执行if语句
if (newState > Fragment.STARTED) {
// 方法执行完毕后,Fragment状态迁移为RESUMED
fragmentStateManager.resume();
}
}
}
...
}
复制代码
至此,Activity的onStart阶段状态转移过程就看完了,通过上面的代码我们知道了,在Activity的onResume阶段,Fragment执行了onResume生命周期回调。
根据上面的讲解,我们可以得到如下调用流程示意:
Activity.onCreate -- begin
Fragment.onAttach
Fragment.onCreate
Fragment.onCreateView
Fragment.onViewCreated
Activity.onCreate -- end
Activity.onStart -- begin
Fragment.onActivityCreated
Fragment.onStart
Activity.onStart -- end
Activity.onResume -- begin
Fragment.onResume
Activity.onResume -- end
复制代码
此时的状态:
- Activity(FragmentManager):RESUMED;
- Fragment:RESUMED。
至此,静态使用Fragment时,Activity生命周期对Fragment的控制,就讲解完毕了。
小结
分析到这一步,我们做一个小结:
- FragmentManager与Activity:FragmentManager就是Activity的一个辅助类,其状态与Activity的生命周期状态同步;Activity在其自己的生命周期回调中,向FragmentManager发起指令,之后FragmentManager对所管理的Fragment进行状态的迁移,具体做法是Activity在生命周期方法中调用FragmentManager的dispatchXX方法,将生命周期事项分发给每一个Fragment;
- Fragment与View:上文中提到了,在layout文件中使用Fragment时,Fragment被解析出来时返回mView,这一点上Fragment的行为很像是一个View,Fragment像View的一面就是因为mView的存在;与View不同的是,Fragment具有自己的生命周期,该生命周期与Activity的生命周期绑定在一起。==有了这个特点,原本需要在Activity的生命周期方法中执行的操作,就可以放在Fragment中进行,这减轻了Activity的工作量==。