[Android]ViewPager+Fragment重建泄漏問題解決

Android組件化架構

我是蒼王,如下是我這個系列的相關文章,有興趣能夠參考一下,能夠給個喜歡或者關注個人文章。 [Android]如何作一個崩潰率少於千分之三噶應用app--章節列表bash

近來遇到一個比較奇怪的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獲取。app

1.在onSaveInstanceState的時候,不調用super的方法,直接調用FragmentActivity.onStateNotSaved(),直接截斷mFragments會恢復棧。但這樣onSaveInstanceState就會沒法恢復狀態,有可能有未知的錯誤,因此不採納 2.在onCreate的流程的時候,先判斷supportFragmentManager.fragments是否有對應的Fragment,而後若是存在就不建立屢次,直接在supportFragmentManager.fragments中獲取。ide

失敗方案,對supportFragmentManager.fragments清空是無效的,supportFragmentManager.fragments是不等價於FragmentActivity.mFragments的函數

這裏還要謹記兩點, 1.onRestoreInstanceState生命週期,是在onCreate以後,在onResume以前的,一些經過恢復的操做,只能在onResume中進行。 2.Application.LifeRecyleCallback沒法監聽到onRestoreInstanceState的執行。 組件化

Android組件化羣2
相關文章
相關標籤/搜索