前言
昨天定位一个线上问题,涉及到Activity和Fragment的生命周期调用先后顺序的问题,今天拿来记录一下这个问题。
正常流程
先看官方给出的生命周期流程图。

这三张图很容易看懂,不多说了,接下来看一下Activity和Fragment的生命周期是如何交错调用的。写一个Activity类,并动态添加一个Fragment,简单贴一下代码

我们一般都是在onCreate中创建fragment并添加到Activity中,执行代码,
1、看APP正常启动时的log:

2、从前台进入后台时的log:

3、从后台进入前台时是log:

4、正常关闭APP时的log:

这些都比较简单。现在我们设想另一种情况,就是APP退入后台一段时间后,由于手机内存紧张被系统杀死了,在这种情况下,再点开APP,其生命周期是怎么样的?
手机内存低APP被杀死后再次打开APP时的log:
02-25 18:38:07.304 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onAttach: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.304 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onCreate: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.305 10048-10048/com.test.wxl D/LifeCycle_ActivityA: onCreate:
02-25 18:38:07.568 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onCreateView: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.580 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onActivityCreated: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.582 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onAttach: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.582 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onCreate: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.583 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onCreateView: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.591 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onActivityCreated: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.592 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onStart: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.593 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onStart: FragmentA{5e5374e #1 id=0x7f070037}
02-25 18:38:07.594 10048-10048/com.test.wxl D/LifeCycle_ActivityA: onStart:
02-25 18:38:07.603 10048-10048/com.test.wxl D/LifeCycle_ActivityA: onResume:
02-25 18:38:07.608 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onResume: FragmentA{f756b52 #0 id=0x7f070037}
02-25 18:38:07.609 10048-10048/com.test.wxl D/LifeCycle_FragmentA: onResume: FragmentA{5e5374e #1 id=0x7f070037}
怎么回事,跟正常打开的时候的生命周期流程不一样,看log,大胆猜测,fragment的相关信息应该是被Activity调用onSaveInstance()方法保存下来。
我们先跟进onCreate(@Nullable Bundle savedInstanceState)的super.onCreate(savedInstanceState)方法、最终来到了FragmentActivity的onCreate(@Nullable Bundle savedInstanceState)方法,贴出代码来看一看

这个方法中,看到最终调用了mFragments.dispatchCreate(),mFragments是一个帮助FragmentManager管理Fragment生命周期的集合,跟进dispatchCreate()方法看一下:
public void dispatchCreate() {
mStateSaved = false;
dispatchStateChange(Fragment.CREATED);
}
中间会调用一次FragmentMannager.java的dispatchCreate()方法,然后
最终来到了FragmentManager.java的moveToState(int newState,boolean always)方法,贴下代码看一下
void moveToState(int newState, boolean always) {
//省略代码
mCurState = newState;//注释1
if (mActive != null) {
boolean loadersRunning = false;
// Must add them in the proper order. mActive fragments may be out of order
//修改已经添加的Fragment的状态
final int numAdded = mAdded.size();
for (int i = 0; i < numAdded; i++) {//注释2
Fragment f = mAdded.get(i);
moveFragmentToExpectedState(f);//注释3
if (f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
// Now iterate through all active fragments. These will include those that are removed
// and detached.
//修改已经移除或者detached的frament的状态
final int numActive = mActive.size();
for (int i = 0; i < numActive; i++) {
Fragment f = mActive.valueAt(i);
if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
moveFragmentToExpectedState(f);
if (f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
}
if (!loadersRunning) {
startPendingDeferredFragments();
}
if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
mHost.onSupportInvalidateOptionsMenu();
mNeedMenuInvalidate = false;
}
}
}
注释1处将mCurState变量赋值,即刚刚传进来的那个Fragment.CREATED。
看注释2处的循环这里简单讲解一下mAdded,mAdded是一个保存了Fragment对象的list,并且list中的fragment的state是Fragment.INITIALIZING型,这个list中的对象是在一开始Fragment被FragmentManager调用add并commit之后的时候被添加进来的。
然后再看下注释3,跟进去发现最终调用了moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive)方法,传进来的参数newState即是刚刚说的那个mCurState,如下
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragments that are not currently added will sit in the onCreate() state.
//省略代码
if (f.mState <= newState) {
//省略代码
//传进来的Fragment对象f的mState=Fragment.INITIALIZING =0
switch (f.mState) {
case Fragment.INITIALIZING:
//而参数newState = Fragment.CREATED=1
if (newState > Fragment.INITIALIZING) {
//省略部分代码
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
// If we have a target fragment, push it along to at least CREATED
// so that this one can rely on it as an initialized dependency.
if (f.mTarget != null) {
if (f.mTarget.mState < Fragment.CREATED) {
moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
}
}
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.mCalled = false;
//重点看这里
f.onAttach(mHost.getContext());//注释3
//.....
if (f.mParentFragment == null) {
mHost.onAttachFragment(f);
} else {
f.mParentFragment.onAttachFragment(f);
}
dispatchOnFragmentAttached(f, mHost.getContext(), false);
if (!f.mIsCreated) {
dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
} else {
f.restoreChildFragmentState(f.mSavedFragmentState);
f.mState = Fragment.CREATED;
}
f.mRetaining = false;
}
// fall through
//省略其他状态
}
}
if (f.mState != newState) {
Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
+ "expected state " + newState + " found " + f.mState);
//更新状态
f.mState = newState;
}
}
注释3的地方,调用了Fragment的onAttached()方法,找到根源了。所以看到了如下现象:当App由于内存紧张被杀死后,再次打开App,Fragment的onAttached方法在Fagment还未添加提交事务前就执行了。
总结
回过头来看ActivityA中的onCreate()添加Fragment的写法对不对,我们通过上面的研究,发现在手机内存降低,被系统杀死之前,Fragment相关的信息会由系统帮我们保存,再次打开App时候,就可以直接在onCreate(@Nullable Bundle savedInstanceState)的参数中取,如果还是按着上面的那种写法,会重复添加Fragment。这势必造成内存的消耗,资源的浪费等一些列问题。所以正确的写法如下:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreate: before super");
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: ");
setContentView(R.layout.activity_a);
if (savedInstanceState!=null){
fragment = getSupportFragmentManager().findFragmentByTag("ActivityA");
return;
}
fragment = new FragmentA();
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container,fragment,"ActivityA");
fragmentTransaction.commit();
}
【附】相关学习资料
Android进阶
移动架构师
需要这些安卓学习资料和面试资料的大伙需要的关注+点赞+加群:185873940 免费获取!
点击链接加入群聊【Android IOC架构设计】:https://jq.qq.com/?_wv=1027&k=5tIZkaU
群内还有许多免费的关于高阶安卓学习资料,包括高级UI、性能优化、架构师课程、 NDK、混合式开发:ReactNative+Weex等多个Android技术知识的架构视频资料,还有职业生涯规划及面试指导。
网友评论