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。