懶加載BaseLazyFragment原理及代碼

懶加載的目的主要是應用于在裝有多個Fragment并進行切換的時候桅打,如viewPager。相信各位在寫項目的時候,肯定也有遇到過viewpager里的fragment進行了前后預加載漱受,即3個fragment的數(shù)據(jù)加載,要通過setOffscreenPageLimit來設置預加載的項目患整,不設置setOffscreenPageLimit拜效,則默認為1(設置0無效喷众,可以查看該方法源碼知道)各谚,即時設置了讓他預加載為0了,也會執(zhí)行多個預加載到千。這個很讓人頭疼昌渤,即大大降低了性能,又浪費初始化資源憔四。然而我們采用懶加載技術(shù)就能讓用戶看到的頁面才會加載他的數(shù)據(jù)膀息,大大提高效率。
懶加載的實現(xiàn)原理就是利用Fragment中的setUserVisibleHint()和onCreateView()了赵,主要是利用了setUserVisibleHint()對fragment的可見狀態(tài)監(jiān)測和在oncreateView()前執(zhí)行的優(yōu)點潜支。注意加載時,如果這個fragment不可見的加載柿汛,那setUserVisibleHint()沒有執(zhí)行冗酿。
當viewPager中fragment改變可見狀態(tài), 使用getUserVisibleHint() 可以返回fragment是否可見狀態(tài):從可見到不見,為false络断;從不可見切換到可見裁替,為true。
可見如圖:具體參考博客****http://blog.csdn.net/mr_immortalz/article/details/51015196

這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

注意:滑動到第三個fragment時貌笨,第一個fragment移除了相關(guān)的視圖但未和活動解除關(guān)聯(lián)弱判。所以從3滑回2時,預加載的1的生命周期少一些執(zhí)行锥惋。

下面我們來看懶加載BaseLazyFragment的class代碼:
1昌腰、首先看setUserVisibleHint()方法的重寫开伏。


第一個判斷語句主要是兩個判斷條件
1)當isVisibleToUser 為true則進行數(shù)據(jù)加載,當isVisibleToUser為false則不進行數(shù)據(jù)加載2)判斷isInit值剥哑,對于已經(jīng)加載過數(shù)據(jù)的fragment硅则,再次被滑動到也不在進行加載數(shù)據(jù),也就是每個fragment僅做一次數(shù)據(jù)加載工作第二個判斷語句是針對以初始化的fragment株婴,再根據(jù)是否可見來判斷顯示怎虫、執(zhí)行生命周期。
2困介、然后回到onCreateView()上大审。在onCreateView()里,對要懶加載的fragment是添加FrameLayout座哩。

如我注釋所寫徒扶,應該比較好理解的吧?(一開始我看了幾篇文章還是很混根穷,直到看了(http://blog.csdn.net/mr_immortalz/article/details/51015196的生命周期演示后姜骡,就大體上有個了解了,各位可以看看屿良。)
3圈澈、然后是對fragment生命周期的處理,每個狀態(tài)下以Fragment的回調(diào)方法名字后面要加個Lazy的方法名命名尘惧,并依此調(diào)用康栈。
注意:onFragmentStopLazy()、onFragmentStartLazy()喷橙、onResumeLazy()在其他地方也有調(diào)用的啥么。

4、加載view贰逾,我們在onCreateView()里悬荣,對要懶加載的fragment是,添加FrameLayout,設置setContentView()是為了當我們將fragment移至可見疙剑,則能夠根據(jù)判斷氯迂,替換掉原來的FrameLayout布局。因為核芽,移至可見時囚戚,該fragment會再次調(diào)用onCreateView()方法嘛。

最后轧简,我貼一下我的代碼驰坊,代碼開頭注釋里講了整體的怎么懶加載思考思路。

package android.davidnba.com.davidnba_ywh.base;

import android.davidnba.com.davidnba_ywh.widget.LoadingDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

/* Created by 仁昌居士 on 2017/2/6.
 * 懶加載Fragment</h1> 只有創(chuàng)建并顯示的時候才會調(diào)用onCreateViewLazy方法
 * 懶加載的原理onCreateView的時候Fragment有可能沒有顯示出來哮独。
 * 但是調(diào)用到setUserVisibleHint(boolean isVisibleToUser),isVisibleToUser =
 * true的時候就說明有顯示出來
 * 但是要考慮onCreateView和setUserVisibleHint的先后問題所以才有了下面的代碼
 * 注意:
 * 《1》原先的Fragment的回調(diào)方法名字后面要加個Lazy拳芙,比如Fragment的onCreateView方法察藐, 就寫成onCreateViewLazy
 * 《2》使用該LazyFragment會導致多一層布局深度
 */


  /*  fragment一共四種情況:
         可見、初始化舟扎;
         可見分飞、未初始化;
         不可見睹限、初始化譬猫;
         不可見、未初始化羡疗;

         邏輯分析染服,假設setOffscreenPageLimit(1),共預加載2個fragment:
         剛進來叨恨,1是可見柳刮,且要初始化的,2是不可見痒钝、未初始化秉颗,第三個3是不綁定到activity的。
         于是送矩,1走途徑1,2走途徑2.

         然后蚕甥,假設滑動了,1滑到2益愈。
           此時梢灭,1不可見夷家,且已初始化了蒸其,2是可見,將要初始化库快,3綁定到activity上摸袁,為不可見、未初始化义屏。
           于是靠汁,1由于預加載的原因,未解除與視圖的聯(lián)系闽铐。所以onPause()蝶怔、onStop()、onDestoryView()未執(zhí)行兄墅,
           并且踢星,由于1不可見,setUserVisibleHint()執(zhí)行了隙咸。所以沐悦, isStart設置為false成洗,即不可見;并調(diào)用onFragmentStopLazy();
           2可見,同理由于預加載原因藏否,處于可見狀態(tài)時瓶殃,不會再調(diào)用onCreateView(),而是會調(diào)用setUserVisibleHint(),
           所以副签,isStart設置為true;onFragmentStartLazy();
           3呢遥椿,調(diào)用onCreateView(),又由于3不可見且未初始化淆储,則不執(zhí)行修壕。所以,加載的是個FrameLayout
         */
public class BaseLazyFragment extends BaseFragment {
    private boolean isInit = false;//真正要顯示的View是否已經(jīng)被初始化(正常加載)
    private Bundle savedInstanceState;
    public static final String INTENT_BOOLEAN_LAZYLOAD = "intent_boolean_lazyload";
    private boolean isLazyLoad = true;
    private FrameLayout layout;
    public LoadingDialog mLoadingDialog;
    private boolean isStart = false;//是否處于可見狀態(tài)遏考,in the screen

    @Override
    protected void onCreateView(Bundle saveInstanceState) {
        super.onCreateView(saveInstanceState);
        Bundle bundle = getArguments();
        if (bundle != null) {
            isLazyLoad = bundle.getBoolean(INTENT_BOOLEAN_LAZYLOAD, isLazyLoad);
        }
        //判斷是否懶加載
        if (isLazyLoad) {
            //一旦isVisibleToUser==true即可對真正需要的顯示內(nèi)容進行加載
            if (getUserVisibleHint() && !isInit) {
                //途徑1
                this.savedInstanceState = saveInstanceState;
                onCreateViewLazy(saveInstanceState);
                isInit = true;
            } else {
                //途徑2
                //如果不可見或者已經(jīng)初始化了
                //進行懶加載
                layout = new FrameLayout(getApplicationContext());
                layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
                super.setContentView(layout);
            }
        } else {
            //途徑3
            //這里是不可見慈鸠,但已經(jīng)初始化了
            //不需要懶加載,開門江山灌具,調(diào)用onCreateViewLazy正常加載顯示內(nèi)容即可
            onCreateViewLazy(saveInstanceState);
            isInit = true;
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        //一旦isVisibleToUser==true即可進行對真正需要的顯示內(nèi)容的加載

        //判斷fragment是否可見青团,是否還未被初始化,該fragment布局是否存在
        //可見咖楣,但還沒被初始化督笆,且該fragment布局存在
        if (isVisibleToUser && !isInit && getContentView() != null) {
            isInit = true; //允許初始化
            onCreateViewLazy(savedInstanceState);//調(diào)用懶加載
            onResumeLazy();
        }
        //對于已經(jīng)加載過數(shù)據(jù)的fragment,再次被滑動到也不在進行加載數(shù)據(jù)诱贿,也就是每個fragment僅做一次數(shù)據(jù)加載工作
        //如果已經(jīng)初始化了娃肿,且該fragment布局存在
        if (isInit && getContentView() != null) {
            if (isVisibleToUser) {
                isStart = true;
                onFragmentStartLazy();
            } else {
                isStart = false;
                onFragmentStopLazy();
            }
        }
    }


    protected void onCreateViewLazy(Bundle savedInstanceState) {
        Log.d("TAG", "onCreateViewLazy() called with: " + "savedInstanceState = [" + savedInstanceState + "]");
    }

    //當Fragment被滑到不可見的位置時,調(diào)用
    protected void onFragmentStopLazy() {
        Log.d("TAG", "onFragmentStopLazy() called with: " + "");
    }

    //當Fragment被滑到可見的位置時珠十,調(diào)用
    protected void onFragmentStartLazy() {
        Log.d("TAG", "onFragmentStartLazy() called with: " + "");

    }

    protected void onResumeLazy() {
        Log.d("TAG", "onResumeLazy() called with: " + "");
    }

    protected void onPauseLazy() {
        Log.d("TAG", "onPauseLazy() called with: " + "");
    }

    protected void onDestroyViewLazy() {

    }


    @Deprecated
    @Override
    public final void onStart() {
        Log.d("TAG", "onStart() : " + "getUserVisibleHint():" + getUserVisibleHint());
        super.onStart();
        if (isInit && !isStart && getUserVisibleHint()) {
            isStart = true;
            onFragmentStartLazy();
        }
    }

    @Deprecated
    @Override
    public final void onStop() {
        super.onStop();
        Log.d("TAG", "onStop() called: " + "getUserVisibleHint():" + getUserVisibleHint());
        if (isInit && isStart && getUserVisibleHint()) {
            isStart = false;
            onFragmentStopLazy();
        }
    }

    @Override
    @Deprecated
    public final void onResume() {
        Log.d("TAG", "onResume() : " + "getUserVisibleHint():" + getUserVisibleHint());
        super.onResume();
        if (isInit) {
            onResumeLazy();
        }
    }

    @Override
    @Deprecated
    public final void onPause() {
        Log.d("TAG", "onPause() : " + "getUserVisibleHint():" + getUserVisibleHint());
        super.onPause();
        if (isInit) {
            onPauseLazy();
        }
    }

    @Override
    @Deprecated
    public final void onDestroyView() {
        Log.d("TAG", "onDestroyView() : " + "getUserVisibleHint():" + getUserVisibleHint());
        super.onDestroyView();
        if (isInit) {
            onDestroyViewLazy();
        }
        isInit = false;
    }

    @Override
    public void setContentView(int layoutResID) {
        //判斷若isLazyLoad==true,移除所有l(wèi)azy view料扰,加載真正要顯示的view
        if (isLazyLoad && getContentView() != null && getContentView().getParent() != null) {
            layout.removeAllViews();
            View view = inflater.inflate(layoutResID, layout, false);
            layout.addView(view);
        }
        //否則,開門見山焙蹭,直接加載真正要顯示的view
        else {
            super.setContentView(layoutResID);
        }
    }

    @Override
    public void setContentView(View view) {
        //判斷若isLazyLoad==true,移除所有l(wèi)azy view晒杈,加載真正要顯示的view
        if (isLazyLoad && getContentView() != null && getContentView().getParent() != null) {
            layout.removeAllViews();
            layout.addView(view);
        }
        //否則,開門見山孔厉,直接加載真正要顯示的view
        else {
            super.setContentView(view);
        }
    }
}

參考博客:
[http://blog.csdn.net/mr_immortalz/article/details/51015196]
http://blog.csdn.net/sinat_15877283/article/details/51037987
http://www.reibang.com/p/58fd611260b5
http://www.open-open.com/lib/view/open1477033083443.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拯钻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子撰豺,更是在濱河造成了極大的恐慌粪般,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件污桦,死亡現(xiàn)場離奇詭異亩歹,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門捆憎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舅柜,“玉大人,你說我怎么就攤上這事躲惰≈路荩” “怎么了?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵础拨,是天一觀的道長氮块。 經(jīng)常有香客問我,道長诡宗,這世上最難降的妖魔是什么滔蝉? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮塔沃,結(jié)果婚禮上蝠引,老公的妹妹穿的比我還像新娘。我一直安慰自己蛀柴,他們只是感情好螃概,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鸽疾,像睡著了一般吊洼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上制肮,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天冒窍,我揣著相機與錄音,去河邊找鬼豺鼻。 笑死综液,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的拘领。 我是一名探鬼主播意乓,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼樱调,長吁一口氣:“原來是場噩夢啊……” “哼约素!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起笆凌,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤圣猎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后乞而,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體送悔,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了欠啤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荚藻。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖洁段,靈堂內(nèi)的尸體忽然破棺而出应狱,到底是詐尸還是另有隱情染乌,我是刑警寧澤唧席,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站怎憋,受9級特大地震影響写半,放射性物質(zhì)發(fā)生泄漏岸蜗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一叠蝇、第九天 我趴在偏房一處隱蔽的房頂上張望璃岳。 院中可真熱鬧,春花似錦悔捶、人聲如沸矾睦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枚冗。三九已至,卻和暖如春蛇损,著一層夾襖步出監(jiān)牢的瞬間赁温,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工淤齐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留股囊,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓更啄,卻偏偏與公主長得像稚疹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子祭务,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容