ViewPager+Fragment重建洩漏問題解決

Android元件化架構
我是蒼王,以下是我這個系列的相關文章,有興趣可以參考一下,可以給個喜歡或者關注我的文章。
[Android]如何做一個崩潰率少於千分之三噶應用app--章節列表近來遇到一個比較奇怪的Fragment問題
app很多時候會使用Viewpager+Fragments的方式顯示佈局,特別是在主頁。
如果app在棧內已經打開了幾個Activity了,突然之間發生崩潰,一般情況下崩潰被捕抓後,會重新恢復試著重新恢復棧頂的崩潰前的Activity。
對於這種崩潰情況,Activity毫無疑問崩潰前會走onSaveInstanceState函式,恢復時會走onRestoreInstanceState恢復場景。
但是當包含ViewPager+Fragments的Activity被觸發恢復後,你會發現竟然這些Fragments會有記憶體洩漏的情況。
分析:
這個非常不容易發現,使用Profile檢視app物件的時候,會發現這些Fragments會被建立了兩次,這種情況是無法通過LeakCanary來偵查到的,因為是主的Activity做出的洩漏。
而且頂上顯示的Fragment並不是Activity所持有的Fragments,如果是某些資料是從Activity中獲取的,將會無法顯示。
原因:
翻閱了原始碼,我們可以看到以下的FragmentActivity恢復的程式碼和重建FragmentActivity的onCreate流程
/** * Save all appropriate fragment state. */ @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); //記錄哪些Fragments被建立了 markFragmentsCreated(); //儲存Fragments狀態 Parcelable p = mFragments.saveAllState(); if (p != null) { outState.putParcelable(FRAGMENTS_TAG, p); } …… } @SuppressWarnings("deprecation") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { mFragments.attachHost(null /*parent*/); super.onCreate(savedInstanceState); if (savedInstanceState != null) { Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG); //棧中的Fragments恢復狀態 mFragments.restoreAllState(p, nc != null ? nc.fragments : null); …… } mFragments.dispatchCreate(); }
這裡可以看到奔潰的時候mFragments的會在onSaveInstanceState被記錄已經建立了,並且會被呼叫了saveAllState,然後重建時onCreate會呼叫restoreAllState,恢復Fragment,然後重新建立一次Fragments,一般情況下super.onCreate會在子類呼叫之前執行,這個時候Fragments的恢復會比子類Activity onCreate要前。
然後重新走onCreate流程,然後重新建立ViewPager和Fragments。那麼Fragments就會被建立兩次了。
解決方法:
無法知道在恢復的mFragments的TAG標誌,所以Activity無法通過TAG獲取。
1.在onSaveInstanceState的時候,不呼叫super的方法,直接呼叫FragmentActivity.onStateNotSaved(),直接截斷mFragments會恢復棧。但這樣onSaveInstanceState就會無法恢復狀態,有可能有未知的錯誤,所以不採納
2.在onCreate的流程的時候,先判斷supportFragmentManager.fragments是否有對應的Fragment,然後如果存在就不建立多次,直接在supportFragmentManager.fragments中獲取。
失敗方案,對supportFragmentManager.fragments清空是無效的,supportFragmentManager.fragments是不等價於FragmentActivity.mFragments的
這裡還要謹記兩點,
1.onRestoreInstanceState生命週期,是在onCreate之後,在onResume之前的,一些通過恢復的操作,只能在onResume中進行。
2.Application.LifeRecyleCallback無法監聽到onRestoreInstanceState的執行。

Android元件化群2