ViewPager+Fragment預加載問題處理

ViewPager+Fragment結合使用的時候,當前顯示的fragment的左右兩邊的fragment也會被創建,在viewPager裏面有個方法setOffscreenPageLimit是設置預加載的fragment數目:

/**
Set the number of pages that should be retained to either side of the
      current page in the view hierarchy in an idle state. Pages beyond this
     limit will be recreated from the adapter when needed.

設置視圖層次結構中處於空閒狀態時應保留到當前頁任一側的頁數。超過此限制的頁將在需要時從適配器重新創建。
**/
public void setOffscreenPageLimit(int limit) {
        if (limit < DEFAULT_OFFSCREEN_PAGES) {
            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
                    + DEFAULT_OFFSCREEN_PAGES);
            limit = DEFAULT_OFFSCREEN_PAGES;
        }
        if (limit != mOffscreenPageLimit) {
            mOffscreenPageLimit = limit;
            populate();
        }
    }

這個方法裏面,至少要預加載左右邊(如果有)各一個fragment。

也就是說,viewpager一定會預先創建當前頁面兩邊還未可見的fragment。

那麼看下fragment的生命週期和setUserVisibleHint()這個方法的調用順序:

setUserVisibleHint():設置Fragment可見或者不可見時會調用此方法。在該方法裏面可以通過調用getUserVisibleHint()獲得Fragment的狀態是可見還是不可見的,如果可見則進行懶加載操作。

onAttach():執行該方法時,Fragment與Activity已經完成綁定,該方法有一個Activity類型的參數,代表綁定的Activity,這時候你可以執行諸如mActivity = activity的操作。

onCreate():初始化Fragment。可通過參數savedInstanceState獲取之前保存的值。

onCreateView():初始化Fragment的佈局。加載佈局和findViewById的操作通常在此函數內完成,但是不建議執行耗時的操作,比如讀取數據庫數據列表。

onActivityCreated():執行該方法時,與Fragment綁定的Activity的onCreate方法已經執行完成並返回,在該方法內可以進行與Activity交互的UI操作,所以在該方法之前Activity的onCreate方法並未執行完成,如果提前進行交互操作,會引發空指針異常。

onStart():執行該方法時,Fragment由不可見變爲可見狀態。

onResume():執行該方法時,Fragment處於活動狀態,用戶可與之交互。

onPause():執行該方法時,Fragment處於暫停狀態,但依然可見,用戶不能與之交互。

onSaveInstanceState():保存當前Fragment的狀態。該方法會自動保存Fragment的狀態,比如EditText鍵入的文本,即使Fragment被回收又重新創建,一樣能恢復EditText之前鍵入的文本。

onStop():執行該方法時,Fragment完全不可見。

onDestroyView():銷燬與Fragment有關的視圖,但未與Activity解除綁定,依然可以通過onCreateView方法重新創建視圖。通常在ViewPager+Fragment的方式下會調用此方法。

onDestroy():銷燬Fragment。通常按Back鍵退出或者Fragment被回收時調用此方法。

onDetach():解除與Activity的綁定。在onDestroy方法之後調用。

Fragment生命週期執行流程(注意紅色的不是生命週期方法):

Fragment創建:setUserVisibleHint()->onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume();

Fragment變爲不可見狀態(鎖屏、回到桌面、被Activity完全覆蓋):onPause()->onSaveInstanceState()->onStop();

Fragment變爲部分可見狀態(打開Dialog樣式的Activity):onPause()->onSaveInstanceState();

Fragment由不可見變爲活動狀態:onStart()->OnResume();

Fragment由部分可見變爲活動狀態:onResume();

退出應用:onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()
(注意退出不會調用onSaveInstanceState方法,因爲是人爲退出,沒有必要再保存數據);

Fragment被回收又重新創建:
被回收執行 onPause()->onSaveInstanceState()->onStop()->onDestroyView()->onDestroy()->onDetach(),
重新創建執行 onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->setUserVisibleHint();

橫豎屏切換:與Fragment被回收又重新創建一樣。

fragment 預創建 --》滑動過去--》再劃回來:          

逐步滑過來,預創建:
setUserVisibleHint-->onAttach-->onCreate-->onCreateView--> onActivityCreated -->
onStart--> onResume --> setUserVisibleHint

逐步划過去:
setUserVisibleHint -->onPause-->onStop-->onDestroyView

逐步劃回來:
setUserVisibleHint -->onCreateView-->onActivityCreated-->onStart-->onResume

如果我們不需要預加載的時候創建還未可見的fragment的對象,生成這裏面的數據佔用太多內存的話,可以結合setUserVisibleHint(boolean isVisibleToUser)這個方法,設置當fragment可見的時候才加載相關數據。這種叫做懶加載,等UI需要展示給用戶的時候,纔去加載數據,而不是提前加載好,可以提高activity的初始化速度,節省用戶的流量。

需要注意的是:如果懶加載的數據要結合UI進行填充展示的話,一定要判斷onCreateView()執行完畢,UI控件都加載進來了才能綁定數據,不然會報空指針異常。因爲結合上面的生命週期的執行流程可以看到setUserVisibleHint這個方法的執行順序可能在onCreateVIew前面,加兩個布爾型的判斷值就可以了。

通常寫一個fragment的基類,在基類裏面處理好懶加載的判斷過程,提供抽象方法給子類fragment再進行相關懶加載操作。

public abstract class BaseFragment extends Fragment {

    private boolean isCreateView = false;

    private boolean isUserVisable = false;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        isCreateView = true;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isCreateView && isVisibleToUser) {
            lazyLoad();
        }
    }

    protected abstract void lazyLoad();
}

參考:簡書的一篇文章

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章