天天看點

Fragment懶加載(二)

之前已經寫了一篇關于懶加載的文章,那為什麼還要重新寫一次呢?因為那是很久之前寫的,而且是引用别人的代碼,最近我又用到了懶加載,但是我發現我看不懂之前寫的文章,是以打算重寫一次。

項目位址:

https://github.com/994866755/handsomeYe.lazyFragment

一、非懶加載情況下的情況

我們做一個viewpager然後寫3個fragment,設定viewpager的緩存為3(.setOffscreenPageLimit(3)),然後在生命周期onCreateView,onResume,onPause,onDestroyView,onDestroy五個方法中列印。發現結果如下:

Fragment懶加載(二)

image.png

展示第一個頁面的時候所有頁面的生命周期都走到onCreate,但是要注意,他們的是都執行,但是執行的順序不固定,但是執行的順序不固定,但是執行的順序不固定。重要的事說三遍。

有時候執行第一個頁面的生命周期前會先執行第二個頁面的,目前我也還沒研究為什麼會發生這種情況。但先記住,以免出BUG,你要是不放心,可以寫一個攔截器,對每個生命周期進行監聽列印。

二、使用懶加載

1. 要使用懶加載,就必須使用setUserVisibleHint這個方法,我們加入這個方法再列印,看看結果:
Fragment懶加載(二)

注意這裡,很重要,它先是全設定false,再把展示的變成true,不過沒關系,因為false false false true這一系列都發生在onCreateView之前,是以這裡可以把這個流程當成true false false。

2. 設定懶加載

要設定懶加載,必須要使用三個參數,我試過很多方法,都要使用三個參數。如果剛開始你直接抄别人的代碼,你肯定記不住三個參數是什麼意義,自己使用setUserVisibleHint才能深刻的記住怎麼去填坑。

(1)假設我什麼都不做,就會出現上圖中的結果。

(2) 首先我定義一個布爾類型,用來判斷是否第一次展示這個頁面,預設是true,展示之後把它變成false,命名為isFristShowFragment;

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        Log.v("lazy","setUserVisibleHint  " + isVisibleToUser);
   
    }
           
@Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        str = getArguments().getString("str");
        Log.v("lazy","onCreateView  "+str);
        view = LayoutInflater.from(getActivity()).inflate(R.layout.layout_textview,null);
        ButterKnife.inject(this,view);

        if (isFristShowFragment && isVisibleToUser) {
            setDataToView();
        }

        return view;
    }
           
private void setDataToView(){
        Log.v("lazy","setDataToView  "+str);
        isFristShowFragment = false;
        tvContent.setText(str);
    }
           

我們這樣寫,在執行擷取資料的setDataToView()加層判斷,如果是第一次顯示并且目前fragment顯示時才調用。然後你發現結果這樣。

Fragment懶加載(二)

這樣沒錯,第一次進來隻加載了第一個頁面的資料,但是你滑動viewpager切換的時候發現第二個頁面第三個頁面都不執行setDataToView(),這是因為onCreate隻執行了一次,你切換也隻執行了setUserVisibleHint方法,是以我們需要多加一個參數并且在setUserVisibleHint方法内做操作。

(3)在setUserVisibleHint内做操作

我的思路是加一個布爾類型isInitView,表示是否執行過初始化的操作,如果執行了就變成true。代碼就變成這樣。

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        Log.v("lazy","setUserVisibleHint  " + isVisibleToUser);
        if (isFristShowFragment && isVisibleToUser && isInitView){
            setDataToView();
        }
    }
           
@Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        isInitView = true;
        str = getArguments().getString("str");
        Log.v("lazy","onCreateView  "+str);
        view = LayoutInflater.from(getActivity()).inflate(R.layout.layout_textview,null);
        ButterKnife.inject(this,view);
        if (isFristShowFragment && isVisibleToUser) {
            setDataToView();
        }
        return view;
    }
           

setDataToView()不變。

你會發現我在onCreateView加一步操作,isInitView = true。執行了初始化的操作後把isInitView 變為true。

你想想,如果不加這個值判斷,直接在setUserVisibleHint中這樣寫:

if (isFristShowFragment && isVisibleToUser ){
            setDataToView();
        }
           

那麼會在onCreatView執行前就執行setDataToView,你想想,在初始化操作之前就執行設定資料操作,那必定報空指針。是以要加個參數確定先執行初始化之後再執行設定資料。

按照上面的做法結果如下:

剛進入顯示第一個頁面時:

Fragment懶加載(二)

切換第二個頁面:

Fragment懶加載(二)

切換第三個頁面:

Fragment懶加載(二)
3. 注意

使用懶加載要注意以下幾點:

(1)這種寫法你無法控制生命周期,fragment的生命周期不歸你直接控制,要不然我使用兩個參數就能實作了,你隻能控制每個生命周期内的方法,相當于在onCreate周期内的操作前加一層判斷。

(2)需要三個參數,不管我怎麼試,這一系列操作都需要三個參數,你可以不按我先這樣的邏輯去寫,但不管你怎麼寫,怎麼設計邏輯,我想都需要三個參數,你隻用設定兩個,另一個isVisibleToUser是由setUserVisibleHint傳入的。

(3)頁面少時使用setOffscreenPageLimit設定全部緩存,本來我都已經處理了你viewpager的預加載,隻要不擔心記憶體占用多,你viewpager本身就為我設定了緩存機制,我就直接一行代碼調用多友善。

繼續閱讀