系统“内存重启”后,Activity和Fragment的生命周期浅谈

前言

昨天定位一个线上问题,涉及到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();
   }
复制代码

最后觉得文章还不错喜欢的点个赞给个喜欢鼓励下呗~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值