首页 > 代码库 > 为Fragment增加入新的生命周期,并实现管理

为Fragment增加入新的生命周期,并实现管理

1.  背景知识

    ViewPager+Fragment实现滑动标签页时,默认情况下,Fragment的生命周期是由FragmentPagerAdapter和Activity共同管理的。
(1) Activity维持在onResume状态时,Fragment的生命周期主要由FragmentPagerAdapter进行管理。进行了预加载的Fragment会处于onResume状态(即使没有变成可操作),预加载多少个Fragment,可以通过    ViewPager::setOffscreenPageLimit()函数进行设置。
   在切换滑动标签页时,已经预加载的Fragment的生命周期不会被触发改变,仍然是onResume。


(2) 当Activity的生命周期发生变化时,所有已经预加载的Fragment的生命周期与Activity保持一致。
   Fragment生命周期与Activity生命周期的关系(主要看onResume和onPause):
     onResume执行顺序 :
        Activity::onResume() -> Fragment::onResume. (Synchronously)
     onPause执行顺序 :
        Fragment::onPause -> Activity::onPause.     (Synchronously)

2.项目需求

    在我们的项目中,因为既需要同时加载多个Fragment, 又需要在Fragment变为可见时做一些事情,不可见时又做一些事情(如切换到该标签页时进行视频播放,退出该标签页时关闭播放),因此,继承Fragment,我们实现自己的MyFragment,在MyFragment中增加了另外两个生命周期: onEnter() (fragment变为可见时回调), onExit()(fragment变为不可见时回调)。这样,我们就可以在onEnter中做开始播放的操作,在onExit中停止播放。

3.解决方案

    根据需求中的描述,增加了两个生命周期后,完整的Fragment的生命周期就变为:
         onCreate()->onCreateView()->onStart()->onResume()->onEnter()->onExit()->onPause()->onStop()->onDestroyView()->onDestroy().

    为了确保生命周期的顺序,需要继承FragmentStatePagerAdapter实现自己的MyFragmentStatePagerAdapter, 重写setPrimaryItem()函数来控制Fragment的生命周期。实现如下:
             MyFragmentStatePagerAdapter::setPrimaryItem(ViewGroup container, int position, Object object) {
                      MyFragment myFragment = (MyFragment)object;
                      if ((myFragment != NULL) && myFragment.isResumed()) {
                          if (myFragment != mpCurrentPrimaryItem) {
                              if (mpCurrentPrimaryItem) {
                                   mpCurrentPrimaryItem.onExit();
                                   mpCurrentPrimaryItem = NULL;
                              }
                              if (myFragment) {
                                  myFragment.onEnter();
                                  mpCurrentPrimaryItem = myFragment;
                             }
                         }
                    }
              }

 

  • MyFragment::onEnter会在几种情况下被执行:

(1)  当Activity是第一次启动时,进入到onResume, 调用ViewPager::setAdapter()函数第一次给ViewPager设置MyFragmentStatePagerAdapter时, 会回调到setPrimaryItem(), 从而使MyFragment进入onEnter.

(2)  若Activity不是第一次进入onResume, 就不能通过ViewPager::setAdapter使fragment进入onEnter了。这时需要在Activity::onResume中给MyFragment设置一个需要进入onEnter的标记,在MyFragment随后进入onResume时(背景知识有说明),找到MyFragment所在的ViewPager,并获取Adapter, 然后调用setPrimaryItem()使自己进入onEnter.

(3)  切换页面时,由MyFragmentStatePagerAdapter::setPrimaryItem()执行。

  • MyFragment::onExit会在两种情况下被执行:

(1) 一种是在Activity执行onPause之后,MyFragmentStatePagerAdapter::setNonePrimaryItem()使MyFragment执行onExit().
MyFragmentStatePagerAdapter::setNonePrimaryItem() {
    if (mpCurrentPrimaryItem) {
        mpCurrentPrimaryItem.onExit();
        mpCurrentPrimaryItem = NULL;
    }
}

需要说明的一点是,由于在Activity onPause之前,已经加载的Fragment会先执行onPause, 所以这种情况下不能确保onExit在onPause之前,这时MyFragmnet生命周期为:onResume()->onEnter()->onPause()->onExit()->onStop(). (这点在我们项目中没有影响)

(2) 第二种是在切换页面时,由MyFragmentStatePagerAdapter::setPrimaryItem()实现。

为Fragment增加入新的生命周期,并实现管理