天天看點

關于 對lazyload的原理進行的學習

一、引言

LazyLoad,見文知意,就是懶惰地加載。理念和單例模式中的懶漢模式有異曲同工之處。

在做一個APP的時候,一個ViewPager包含多個Fragment,如果在打開APP的時候每個fragment自動加載,不管是從本地還是網絡,都會占用一定的資源。

那我們可以不可以讓這個fragment在需要被顯示的時候才去加載、初始化呢?

在Fragment中有一個方法——setUserVisibleHint就能實作這個設想。

二、setUserVisibleHint的使用

setUserVisibleHint方法用于告訴系統,這個Fragment的界面對使用者目前是否是可見的。是以我們隻需要繼承Fragment并重寫該方法,即可實作在fragment可見時才進行資料加載操作,即Fragment的懶加載。

代碼解釋:

1.代碼開始先設定标志變量isInit代表視圖是否已經初初始化,在視圖初始化的時候設定為true

标志變量isLoad代表視圖是否對使用者可見,在視圖可見時設為true

2.定義了一個判斷是否可以加載資料的方法isCanLoadData() ,*可以加載資料的條件:

* 1.視圖已經初始化,isInit==true

* 2.視圖對使用者可見,getUserVisibleHint()傳回true

3.定義了一個lazyLoad的抽象方法,該方法在isCanLoadData()裡面調用。起到當視圖初始化并且對使用者可見的時候去真正的加載資料的作用。

4.定義了一個stopLoad方法,用于在切換到其他頁面時停止加載資料。

5.定義方法onDestroyView,視圖銷毀的時候将Fragment的狀态是否初始化變為false。

isInit = false;

isLoad = false;

6.視圖是否已經對使用者可見,系統的方法setUserVisibleHint(),在其中調用 isCanLoadData方法,實作Fragment資料的緩加載.

代碼:

public abstract class LazyLoadFragment extends Fragment {
        /**
         * 視圖是否已經初初始化
         */
    protected boolean isInit = false;
    protected boolean isLoad = false;
    protected final String TAG = "LazyLoadFragment";
    private View view;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(setContentView(), container, false);
        isInit = true;
        /**初始化的時候去加載資料**/
        isCanLoadData();
        return view;
    }

    /**
     * 視圖是否已經對使用者可見,系統的方法
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        isCanLoadData();
    }

    /**
     * 是否可以加載資料
     * 可以加載資料的條件:
     * 1.視圖已經初始化
     * 2.視圖對使用者可見
     */
    private void isCanLoadData() {
        if (!isInit) {
            return;
        }
        if (getUserVisibleHint()) {
            lazyLoad();
            isLoad = true;
        } else {
            if (isLoad) {
                stopLoad();
            }
        }
    }

    /**
     * 視圖銷毀的時候講Fragment是否初始化的狀态變為false
     */
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        isInit = false;
        isLoad = false;
    }

    protected void showToast(String message) {
        if (!TextUtils.isEmpty(message)) {
            Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 設定Fragment要顯示的布局
     *
     * @return 布局的layoutId
     */
    protected abstract int setContentView();

    /**
     * 擷取設定的布局
     *
     * @return
     */
    protected View getContentView() {
        return view;
    }

    /**
     * 找出對應的控件
     *
     * @param id
     * @param <T>
     * @return
     */
    protected <T extends View> T findViewById(int id) {
        return (T) getContentView().findViewById(id);
    }

    /**
     * 當視圖初始化并且對使用者可見的時候去真正的加載資料
     */
    protected abstract void lazyLoad();

    /**
     * 當視圖已經對使用者不可見并且加載過資料,如果需要在切換到其他頁面時停止加載資料,可以覆寫此方法
     */
    protected void stopLoad() {
    }
}
           

三、注意

isCanLoadData方法也在onCreateView中進行了調用,是因為要進行初始化的工作,畢竟ViewPager是會預設顯示第一頁的。setUserVisibleHint 的執行順序又是在 onCreatView 之前,同時 onCreatView 需要初始化界面和修改 isInit 的值。

setUserVisibleHint 的執行順序是

setUserVisibleHint(false) -> onAttach -> onCreate -> setUserVisibleHint(true) -> onCreateView -> onActivityCreated ->…. -> onDetach參考ITluochen同學的blog