之前已經寫了一篇關于懶加載的文章,那為什麼還要重新寫一次呢?因為那是很久之前寫的,而且是引用别人的代碼,最近我又用到了懶加載,但是我發現我看不懂之前寫的文章,是以打算重寫一次。
項目位址:
https://github.com/994866755/handsomeYe.lazyFragment一、非懶加載情況下的情況
我們做一個viewpager然後寫3個fragment,設定viewpager的緩存為3(.setOffscreenPageLimit(3)),然後在生命周期onCreateView,onResume,onPause,onDestroyView,onDestroy五個方法中列印。發現結果如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuYjYkZzN2MzYhZTN2ITOxEGNwgjYmhjNjdjM5cjNmF2NfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
image.png
展示第一個頁面的時候所有頁面的生命周期都走到onCreate,但是要注意,他們的是都執行,但是執行的順序不固定,但是執行的順序不固定,但是執行的順序不固定。重要的事說三遍。
有時候執行第一個頁面的生命周期前會先執行第二個頁面的,目前我也還沒研究為什麼會發生這種情況。但先記住,以免出BUG,你要是不放心,可以寫一個攔截器,對每個生命周期進行監聽列印。
二、使用懶加載
1. 要使用懶加載,就必須使用setUserVisibleHint這個方法,我們加入這個方法再列印,看看結果:
注意這裡,很重要,它先是全設定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顯示時才調用。然後你發現結果這樣。
這樣沒錯,第一次進來隻加載了第一個頁面的資料,但是你滑動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,你想想,在初始化操作之前就執行設定資料操作,那必定報空指針。是以要加個參數確定先執行初始化之後再執行設定資料。
按照上面的做法結果如下:
剛進入顯示第一個頁面時:
切換第二個頁面:
切換第三個頁面:
3. 注意
使用懶加載要注意以下幾點:
(1)這種寫法你無法控制生命周期,fragment的生命周期不歸你直接控制,要不然我使用兩個參數就能實作了,你隻能控制每個生命周期内的方法,相當于在onCreate周期内的操作前加一層判斷。
(2)需要三個參數,不管我怎麼試,這一系列操作都需要三個參數,你可以不按我先這樣的邏輯去寫,但不管你怎麼寫,怎麼設計邏輯,我想都需要三個參數,你隻用設定兩個,另一個isVisibleToUser是由setUserVisibleHint傳入的。
(3)頁面少時使用setOffscreenPageLimit設定全部緩存,本來我都已經處理了你viewpager的預加載,隻要不擔心記憶體占用多,你viewpager本身就為我設定了緩存機制,我就直接一行代碼調用多友善。