昨天定位一个线上问题,涉及到Activity和Fragment的生命周期调用前后顺序的问题,今天拿来记录一下这个问题。java
先看官方给出的生命周期流程图。bash
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)方法,贴出代码来看一看ide
public void dispatchCreate() {
mStateSaved = false;
dispatchStateChange(Fragment.CREATED);
}
复制代码
中间会调用一次FragmentMannager.java的dispatchCreate()方法,而后 最终来到了FragmentManager.java的moveToState(int newState,boolean always)方法,贴下代码看一下ui
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,以下this
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还未添加提交事务前就执行了。spa
回过头来看ActivityA中的onCreate()添加Fragment的写法对不对,咱们经过上面的研究,发如今手机内存下降,被系统杀死以前,Fragment相关的信息会由系统帮咱们保存,再次打开App时候,就能够直接在onCreate(@Nullable Bundle savedInstanceState)的参数中取,若是仍是按着上面的那种写法,会重复添加Fragment。这势必形成内存的消耗,资源的浪费等一些列问题。因此正确的写法以下:3d
@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();
}
复制代码
最后以为文章还不错喜欢的点个赞给个喜欢鼓励下呗~rest