? ? ? ?最近客戶反饋幾個ViewPager中帶Fragment無法感知生命周期的問題弛矛。所以對v4包對源碼分析一下∫我埃現(xiàn)在把結(jié)果分享一下瞒瘸。
? ? ? 很多開發(fā)者在開發(fā)ViewPager的時候双戳,都會帶上預(yù)加載功能戏蔑。常見有FragmentPagerAdapter與FragmentStatePagerAdapter配合ViewPager使用叹洲,或者完全自定義實現(xiàn)PagerAdapter柠硕。ViewPager的預(yù)加載功能會把左右相鄰Fragment緩存起來,因此Fragment的生命周期在預(yù)加載的時候就會被提前調(diào)用运提,或者沒有調(diào)用蝗柔。因此GrowingIO 無法trace目標Fragment。
? ? ? ?所以解決GrowingIO無法track Fragment問題首先了解ViewPager如何配合PagerAdapter對多個Fragment進行管理民泵。先從ViewPager預(yù)加載相鄰Fragment開始癣丧。具體邏輯見如下源碼:
? ? ? ?上圖的邏輯是預(yù)加載左邊Fragment的代碼栈妆,位于ViewPager.pupolate()函數(shù)中胁编,其中1代碼區(qū)代碼含義是若當前緩存Fragment寬度不合適或位置不對,調(diào)用destoryItem銷毀目標Fragment鳞尔。3代碼區(qū)是若目標Fragment不存在調(diào)用addNewItem添加新的Fragment嬉橙。
? ? ? ? 預(yù)初始化Fragment邏輯在addNewItem中,源碼如下:
? ? ? ?見上圖代碼市框,addNewItem通過Adapter.instantiateItem函數(shù)初始化Fragment。
? ? ? ?右邊相鄰的Fragment同理糕韧,所以略枫振。
? ? ? ?這就是為什么預(yù)加載相鄰Fragment時喻圃,生命周期會被提前調(diào)用對原因。
? ? ? ?下面我們來看粪滤,顯示當前頁是怎樣顯示的斧拍。
? ? ? ?當前也的顯示與更新是在主要依賴PageAdapter頁面杖小。setPrimaryItem是顯示當前頁面饮焦,finishUpdate是頁面更新結(jié)束。
? ? ? ?由上面對ViewPager源碼分析窍侧,我們清楚知道ViewPager通過PagerAdapter實現(xiàn)對Fragment對管理县踢。PagerAdapter關(guān)鍵函數(shù)有:
instantiateItem: 根據(jù)位置,初始化列表對應(yīng)Fragment伟件。
setPrimaryItem:根據(jù)當前位置與當前Fragment對象硼啤,顯示當前Fragment。
finishUpdate:完成當前顯示Fragment頁面刷新斧账。
destroyItem:銷毀傳入對Fragment對象谴返。
? ? ? ?那問題來了,如何識別正在顯示對Fragment 與預(yù)加載Fragment咧织?
? ? ? ?答案是:Fragment.setUserVisibleHint.
? ? ? ?官方文檔對該函數(shù)對解釋是:告知系統(tǒng)當前Fragment是否對用戶顯示嗓袱。
? ? ? ?所以在setPrimaryItem的實現(xiàn)代碼中應(yīng)該調(diào)用setUserVisibleHint(true),在instantiateItem的實現(xiàn)代碼中习绢,應(yīng)該調(diào)用setUserVisibleHint(false)渠抹。v4提供的FragmentStatePagerAdapter、FragmentPageAdapter已經(jīng)實現(xiàn)該調(diào)用闪萄,最好直接調(diào)用梧却。
? ? ? ?規(guī)范PageAdapter的寫法后,無縫接入GrowingIO無埋點SDK败去,幫助你的應(yīng)用增長吧放航。
關(guān)鍵詞:Android、GrowingIO圆裕、ViewPager广鳍、Fragment、setUserVisibleHint吓妆、預(yù)加載赊时。