1. 程式人生 > >Fragment中呼叫getActivity為null的問題

Fragment中呼叫getActivity為null的問題

在使用fragment的時候經常會遇到getActivity()為null的情況。比如我在一個非同步網路請求的回撥中呼叫了getActivity()就會出現空指標問題。之前解決這個問題,通常都是直接加空指標判斷來規避,但是這並沒有真正解決問題。

    很多人都曾被這個問題所困擾,如果app長時間在後臺執行,再次進入app的時候可能會出現crash,而且fragment會有重疊現象。如果系統記憶體不足、切換橫豎屏、app長時間在後臺執行,Activity都可能會被系統回收然後重建,但Fragment並不會隨著Activity的回收而被回收,建立的所有Fragment會被儲存到Bundle裡面,

從而導致Fragment丟失對應的Activity。

下面是FragmentActivity的部分原始碼

    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
 Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(
 "android:support:fragments", p);
        }

    }

如果從最近使用的應用裡面點選我們的應用,系統會恢復之前被回收的Activity,這個時候FragmentActivity在oncreate裡面也會做Fragment的恢復,

@Override
    protected void onCreate(Bundle savedInstanceState) {
        mFragments.attachActivity(this, mContainer, null);
        // Old versions of the platform didn't do this!
        if (getLayoutInflater().getFactory() == null) {
            getLayoutInflater().setFactory(this);
        }
        super.onCreate(savedInstanceState);      
        NonConfigurationInstances nc = (NonConfigurationInstances)
                getLastNonConfigurationInstance();
        if (nc != null) {
            mAllLoaderManagers = nc.loaders;
        }
       

 if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        }
        mFragments.dispatchCreate();

    }

    假設我們的頁面叫MyActivity(繼承自FragmentActivity),其中用到的Fragment叫MyFragment。

    出現上面這種情況時,app發生的變化如下:

1、在前面提到的幾種情況下系統回收了MyActivity

2、通過onSaveInstanceState儲存MyFragment的狀態

3、使用者再次點選進入app

4、由於MyActivity被回收,系統會重啟MyActivity根據之前儲存的MyFragment的狀態恢復fragment

5、MyActivity的程式碼邏輯中,會再次建立新的MyFragment

6、頁面出現混亂,覆蓋了兩層的fragment。假如恢復的MyFragment使用到了getActivity()方法,會報空指標異常

    對於上面的問題,可以考慮下面這兩種解決辦法:

   1、不儲存fragment的狀態:在MyActivity中重寫onSaveInstanceState方法,將super.onSaveInstanceState(outState);註釋掉,讓其不再儲存Fragment的狀態,達到fragment隨MyActivity一起銷燬的目的。

2、重建時清除已經儲存的fragment的狀態在恢復Fragment之前把Bundle裡面的fragment狀態資料給清除。方法如下:

if(savedInstanceState!= null)

        {
            String FRAGMENTS_TAG =  "android:support:fragments";
            savedInstanceState.remove(FRAGMENTS_TAG);

        }