ViewPager配合不同的PagerAdapter,对应Fragment的生命周期有着不同的表现,了解这个生命周期机制对于开发者选择合适的PagerAdapter实现不同的效果,有着很大的帮助。
FragmentPagerAdapter和FragmentStatePagerAdapter的区别:
- FragmentPagerAdapter:
类内的每一个生成的 Fragment
都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种;如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,应该使用FragmentStatePagerAdapter。 - FragmentStatePagerAdapter:
正如其类名中的 ‘State’ 所表明的含义一样,该 PagerAdapter
的实现将只保留当前页面,当页面离开视线后,就会被消除,释放其资源; 而在页面需要显示时,生成新的页面(就像 ListView的实现一样)。这么实现的好处就是当拥有大量的页面时,不必在内存中占用大量的内存。
viewPager.setOffscreenPageLimit(X)对Fragment创建时机的影响:
如果ViewPager下有N个fragments,并设置了setOffscreenPageLimit(X),则当fragment1用户可见时,其后面X个fragment也已经同fragment1一同预先创建完成。当滑动fragment1->fragment2时,第X+2个fragment完成创建,以保持当前fragment(fragment2)后有X个fragment已经创建完成作为缓存。
- FragmentPagerAdapter和FragmentStatePagerAdapter差别:
如前面提到FragmentPagerAdapter不会释放创建过的fragment,这样当fragment1->fragmentN完成以轮切换后,从fragmentN->fragment1反方向切换时,不会再触发fragment的创建,即onCreate()不会被调用。
而FragmentStatePagerAdapter做从fragmentN->fragment1反方向切换时则会继续触发fragment的创建以保障有X个fragment被创建并缓存着(因为大于X的fragment已经被释放了)
总结:fragment的onCreate()总是预先被调用,且被调用的时机总是同当前用户可见的fragment保持X个fragment的“距离“,即某个fragment的onCreate()被调用时,它的前X个fragment是用户可见的。
奇怪的onResume():前面说明了onCreate()被触发的规律,但是onResume()的触发规律则十分奇怪,eg:有以下fragment,f1,f2,f3,f4当f1->f2时,f2的onResume()被触发,当f2->f3时,f3的onResume()被触发,当f3->f2时,f2的onResume()不会被触发,当f2->f3时,f3的onResume()仍然被触发,鉴于这个onResume()被触发的规律很“混乱”,所以不宜做一些需要确定性的任务。(后面有机会在研究下了)
实际应用:
当fragment切换至用户可见后,要做一些处理,比如请求网络数据,更新当前页面等。
经过前面的分析可知onCreate()和onResume()的触发时机都不满足以上要求:onCreate()会预创建,FragmentPagerAdapter下还会一直缓存,onResume()的触发时机又没有规律(正常情况下大家对于这种需求一般会想到resume()这类接口)。
我们可以利用setUserVisibleHint()接口实现该功能,即当本fragment为用户可见时,该接口被触发,以达到每次fragment切换为可见后,更新当前fragment页面数据的目的。
实现类似网易新闻客户端,ViewPager每次只加载当前页。
如前所诉,使用FragmentPagerAdapter或者FragmentStatePagerAdapter都会默认多加载X页(X通过setOffscreenPageLimit()设置,最小值为1)。
这个需求同样通过setUserVisibleHint()来实现,将网络请求加载页面的处理,从onCreate()中移到setUserVisibleHint()中,这样就实现了切换到页面才进行更新的效果。
notes:貌似在某些厂商的rom上对FragmentPagerAdapter的缓存机制做了改动,导致缓存失效,这样就要十分小心对缓存fragment生命周期的处理,尽量避免引用不在前台展示的fragment。