成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ViewPager懶加載極致優(yōu)化

gotham / 871人閱讀

摘要:最后,當(dāng)一次更新添加和或移除完成之后將會(huì)調(diào)用來(lái)通知提交關(guān)聯(lián)和或取消關(guān)聯(lián)的操作。懶加載的實(shí)現(xiàn)弊端概念當(dāng)需要時(shí)才加載,加載之后一直保持該對(duì)象。而且為了實(shí)現(xiàn)滑動(dòng)效果,都是預(yù)加載左右兩側(cè)的頁(yè)面。預(yù)加載的預(yù)加載機(jī)制。

目錄介紹

01.ViewPager簡(jiǎn)單介紹

02.ViewPager弊端分析

03.ViewPager預(yù)加載

04.ViewPager部分源碼

05.懶加載出現(xiàn)問(wèn)題

06.如何實(shí)現(xiàn)預(yù)加載機(jī)制

07.懶加載配合狀態(tài)管理器

好消息

博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時(shí)開(kāi)發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長(zhǎng)期更新維護(hù)并且修正,持續(xù)完善……開(kāi)源的文件是markdown格式的!同時(shí)也開(kāi)源了生活博客,從12年起,積累共計(jì)N篇[近100萬(wàn)字,陸續(xù)搬到網(wǎng)上],轉(zhuǎn)載請(qǐng)注明出處,謝謝!

鏈接地址:https://github.com/yangchong2...

如果覺(jué)得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬(wàn)事起于忽微,量變引起質(zhì)變!

01.ViewPager簡(jiǎn)單介紹

ViewPager使用一個(gè)鍵對(duì)象來(lái)關(guān)聯(lián)每一頁(yè),而不是管理View。這個(gè)鍵用于追蹤和唯一標(biāo)識(shí)在adapter中獨(dú)立位置中的一頁(yè)。調(diào)用方法startUpdate(ViewGroup)表明ViewPager中的內(nèi)容需要更改。

通過(guò)調(diào)用一次或多次調(diào)用instantiateItem(ViewGroup, int)來(lái)構(gòu)造頁(yè)面視圖。

調(diào)用destroyItem(ViewGroup, int, Object)來(lái)取消ViewPager關(guān)聯(lián)的頁(yè)面視圖。

最后,當(dāng)一次更新(添加和/或移除)完成之后將會(huì)調(diào)用finishUpdate(ViewGroup)來(lái)通知adapter, 提交關(guān)聯(lián)和/或取消關(guān)聯(lián)的操作。這三個(gè)方法就是用于ViewPager使用回調(diào)的方式來(lái)通知PagerAdapter來(lái)管理其中的頁(yè)面。

一個(gè)非常簡(jiǎn)單的方式就是使用每頁(yè)視圖作為key來(lái)關(guān)聯(lián)它們自己,在方法instantiateItem(ViewGroup, int)中創(chuàng)建和添加它們到ViewGroup之后,返回該頁(yè)視圖。與之相匹配的方法destroyItem(ViewGroup, int, Object)實(shí)現(xiàn)從ViewGroup中移除視圖。當(dāng)然必須在isViewFromObject(View, Object)中這樣實(shí)現(xiàn):return view == object;.

PagerAdapter支持?jǐn)?shù)據(jù)改變時(shí)刷新界面,數(shù)據(jù)改變必須在主線程中調(diào)用,并在數(shù)據(jù)改變完成后調(diào)用方法notifyDataSetChanged(), 和AdapterView中派生自BaseAdapter相似。一次數(shù)據(jù)的改變可能關(guān)聯(lián)著頁(yè)面的添加、移除、或改變位置。ViewPager將根據(jù)adapter中實(shí)現(xiàn)getItemPosition(Object)方法返回的結(jié)果,來(lái)判斷是否保留當(dāng)前已經(jīng)構(gòu)造的活動(dòng)頁(yè)面(即重用,而不完全自行構(gòu)造)。

02.ViewPager弊端分析

普通的viewpager如果你不使用setoffscreenpagelimit(int limit)這個(gè)方法去設(shè)置默認(rèn)加載數(shù)的話是會(huì)默認(rèn)加載頁(yè)面的左右兩頁(yè)的,也就是說(shuō)當(dāng)你進(jìn)入viewpager第一頁(yè)的時(shí)候第二頁(yè)和第一頁(yè)是會(huì)被一起加載的,這樣同時(shí)加載就會(huì)造成一些問(wèn)題,試想我們?nèi)绻O(shè)置了setoffscreenpagelimit為3的話,那么進(jìn)入viewpager以后就會(huì)同時(shí)加載4個(gè)fragment,像我們平時(shí)的項(xiàng)目中在這些fragment中一般都是會(huì)發(fā)送網(wǎng)絡(luò)請(qǐng)求的,也就是說(shuō)我們有4個(gè)fragment同時(shí)發(fā)送網(wǎng)絡(luò)請(qǐng)求去獲取數(shù)據(jù),這樣的結(jié)果顯而易見(jiàn)給用戶的體驗(yàn)是不好的(如:浪費(fèi)用戶流量,造成卡頓等等)。

懶加載的實(shí)現(xiàn)弊端

概念:當(dāng)需要時(shí)才加載,加載之后一直保持該對(duì)象。

而關(guān)于Fragment實(shí)現(xiàn)的PagerAdapter都沒(méi)有完全保存其引用和狀態(tài)。FragmentPageAdapter需要重建視圖,F(xiàn)ragmentStatePageAdapter使用狀態(tài)恢復(fù),View都被銷毀,但是恢復(fù)的方式不同,而通常我們想得到的結(jié)果是,F(xiàn)ragment一旦被加載,其視圖也不會(huì)被銷毀,即不會(huì)再重新走一遍生命周期。而且ViewPager為了實(shí)現(xiàn)滑動(dòng)效果,都是預(yù)加載左右兩側(cè)的頁(yè)面。

我們通常想要實(shí)現(xiàn)的兩種效果:不提供滑動(dòng),需要時(shí)才構(gòu)造,并且只走一遍生命周期,避免在Fragment中做過(guò)多的狀態(tài)保存和恢復(fù)。

03.ViewPager預(yù)加載

ViewPager的預(yù)加載機(jī)制。那么,我們可不可以設(shè)置ViewPager的預(yù)加載為0,不就解決問(wèn)題了嗎?也就是代碼這樣操作:

vp.setOffscreenPageLimit(0);

然后看一下源碼

即使你設(shè)置為0,那么還是會(huì)在里面判斷后設(shè)為默認(rèn)值1。所以這個(gè)方法是行不通的。

public void setOffscreenPageLimit(int limit) {
    if (limit < 1) {
        Log.w("ViewPager", "Requested offscreen page limit " + limit + " too small; defaulting to " + 1);
        limit = 1;
    }

    if (limit != this.mOffscreenPageLimit) {
        this.mOffscreenPageLimit = limit;
        this.populate();
    }

}

ViewPager默認(rèn)情況下的加載,當(dāng)切換到當(dāng)前頁(yè)面時(shí),會(huì)默認(rèn)預(yù)加載左右兩側(cè)的布局到ViewPager中,盡管兩側(cè)的View并不可見(jiàn)的,我們稱這種情況叫預(yù)加載;由于ViewPager對(duì)offscreenPageLimit設(shè)置了限制,頁(yè)面的預(yù)加載是不可避免……

初始化緩存(mOffscreenPageLimit == 1)

當(dāng)初始化時(shí),當(dāng)前顯示頁(yè)面是第0頁(yè);mOffscreenPageLimit為1,所以預(yù)加載頁(yè)面為第1頁(yè),再往后的頁(yè)面就不需要加載了(這里的2, 3, 4頁(yè))

中間頁(yè)面緩存(mOffscreenPageLimit == 1)

當(dāng)向右滑動(dòng)到第2頁(yè)時(shí),左右分別需要緩存一頁(yè),第0頁(yè)就需要銷毀掉,第3頁(yè)需要預(yù)加載,第4頁(yè)不需要加載

04.ViewPager部分源碼

ViewPager.setAdapter方法

銷毀舊的Adapter數(shù)據(jù),用新的Adaper更新UI

清除舊的Adapter,對(duì)已加載的item調(diào)用destroyItem,

將自身滾動(dòng)到初始位置this.scrollTo(0, 0)

設(shè)置PagerObserver: mAdapter.setViewPagerObserver(mObserver);

調(diào)用populate()方法計(jì)算并初始化View(這個(gè)方法后面會(huì)詳細(xì)介紹)

如果設(shè)置了OnAdapterChangeListener,進(jìn)行回調(diào)

ViewPager.populate(int newCurrentItem)

該方法是ViewPager非常重要的方法,主要根據(jù)參數(shù)newCurrentItem和mOffscreenPageLimit計(jì)算出需要初始化的頁(yè)面和需要銷毀頁(yè)面,然后通過(guò)調(diào)用Adapter的instantiateItem和destroyItem兩個(gè)方法初始化新頁(yè)面和銷毀不需要的頁(yè)面!

根據(jù)newCurrentItem和mOffscreenPageLimit計(jì)算要加載的page頁(yè)面,計(jì)算出startPos和endPos

根據(jù)startPos和endPos初始化頁(yè)面ItemInfo,先從緩存里面獲取,如果沒(méi)有就調(diào)用addNewItem方法,實(shí)際調(diào)用mAdapter.instantiateItem

將不需要的ItemInfo移除: mItems.remove(itemIndex),并調(diào)用mAdapter.destroyItem方法

設(shè)置LayoutParams參數(shù)(包括position和widthFactor),根據(jù)position排序待繪制的View列表:mDrawingOrderedChildren,重寫(xiě)了getChildDrawingOrder方法

最后一步獲取當(dāng)前顯示View的焦點(diǎn):currView.requestFocus(View.FOCUS_FORWARD)

ViewPager.dataSetChanged()

當(dāng)調(diào)用Adapter的notifyDataSetChanged時(shí),會(huì)觸發(fā)這個(gè)方法,該方法會(huì)重新計(jì)算當(dāng)前頁(yè)面的position,

移除需要銷毀的頁(yè)面的ItemInfo對(duì)象,然后再調(diào)用populate方法刷新頁(yè)面

循環(huán)mItems(每個(gè)page對(duì)應(yīng)的ItemInfo對(duì)象),調(diào)用int newPos = mAdapter.getItemPosition方法

當(dāng)newPos等于PagerAdapter.POSITION_UNCHANGED表示當(dāng)前頁(yè)面不需要更新,不用銷毀,當(dāng)newPos等于PagerAdapter.POSITION_NONE時(shí),需要更新,移除item,調(diào)用mAdapter.destroyItem

循環(huán)完成后,最后計(jì)算出顯示頁(yè)面的newCurrItem,調(diào)用setCurrentItemInternal(newCurrItem, false, true)方法更新UI(實(shí)際調(diào)用populate方法重新計(jì)算頁(yè)面信息)

ViewPager.scrollToItem(int item, boolean smoothScroll, int velocity, boolean dispatchSelected)

滑動(dòng)到指定頁(yè)面,內(nèi)部會(huì)觸發(fā)OnPageChangeListener

ViewPager.calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo)

這個(gè)方法主要用于計(jì)算每個(gè)頁(yè)面對(duì)應(yīng)ItemInfo的offset變量,這個(gè)變量用于記錄當(dāng)前view在所有緩存View中(包含當(dāng)前顯示頁(yè))的索引,用于布局的時(shí)候計(jì)算該View應(yīng)該放在哪個(gè)位置

在populate方法中更新完頁(yè)面數(shù)據(jù)后,會(huì)調(diào)用該方法計(jì)算所有頁(yè)面的offset

05.懶加載出現(xiàn)問(wèn)題

發(fā)現(xiàn)Fragment中有一個(gè)setUserVisibleHint(boolean isVisibleToUser)方法,這個(gè)方法就是告訴用戶,UI對(duì)用戶是否可見(jiàn),可以做懶加載初始化操作。

因?yàn)閂iewPager會(huì)加載好多Fragment,為了節(jié)省內(nèi)容等會(huì)在Fragment不可見(jiàn)的某個(gè)時(shí)候調(diào)用onDestroyView()將用戶界面銷毀掉但是Fragment的實(shí)例還在,所以可能第一次加載沒(méi)有問(wèn)題,但是再次回到第一個(gè)Fragment再去加載的時(shí)候就會(huì)出現(xiàn)UI對(duì)用戶可見(jiàn)但是視圖還沒(méi)有初始化。

懶加載需要處理的幾個(gè)問(wèn)題

預(yù)加載,雖然沒(méi)有顯示在界面上,但是當(dāng)前頁(yè)面的上一頁(yè)和下一頁(yè)的Fragment已經(jīng)執(zhí)行了一個(gè)Fragment能夠顯示在界面上的所有生命周期方法,但是我們想在跳轉(zhuǎn)到該頁(yè)時(shí)才真正構(gòu)造數(shù)據(jù)視圖和請(qǐng)求數(shù)據(jù)。那么我們可以使用一個(gè)占位視圖,那么可以想到使用ViewStub,當(dāng)真正跳轉(zhuǎn)到該頁(yè)時(shí),執(zhí)行ViewStub.inflate()方法,加載真正的數(shù)據(jù)視圖和請(qǐng)求數(shù)據(jù)。

視圖保存

當(dāng)某一頁(yè)超出可視范圍和預(yù)加載范圍,那么它將會(huì)被銷毀,F(xiàn)ragmentStatePagerAdapter銷毀整個(gè)Fragment, 我們可以自己保存該Fragment,或使用FragmentPagerAdapter讓FragmentTransition來(lái)保留Fragment的引用。雖然這樣,但是它的周期方法已經(jīng)走完,那么我們只能手動(dòng)的保存Fragment根View的引用,當(dāng)再次重新進(jìn)入新的聲明周期方法時(shí),返回原來(lái)的View

是否已經(jīng)被用戶所看到

其實(shí)本身而言,F(xiàn)ragmentManager并沒(méi)有提供為Fragment被用戶所看到的回調(diào)方法,而是在FragmentPagerAdapter和FragmentStatePagerAdapter中,調(diào)用了Fragment.setUserVisibleHint(boolean)來(lái)表明Fragment是否已經(jīng)被作為primaryFragment. 所以這個(gè)方法可以被認(rèn)為是一個(gè)回調(diào)方法。

06.如何實(shí)現(xiàn)預(yù)加載機(jī)制

主要的方法是Fragment中的setUserVisibleHint(),此方法會(huì)在onCreateView()之前執(zhí)行,當(dāng)viewPager中fragment改變可見(jiàn)狀態(tài)時(shí)也會(huì)調(diào)用,當(dāng)fragment 從可見(jiàn)到不見(jiàn),或者從不可見(jiàn)切換到可見(jiàn),都會(huì)調(diào)用此方法,使用getUserVisibleHint() 可以返回fragment是否可見(jiàn)狀態(tài)。

在BaseLazyFragment中需要在onActivityCreated()及setUserVisibleHint()方法中都調(diào)了一次lazyLoad() 方法。如果僅僅在setUserVisibleHint()調(diào)用lazyLoad(),當(dāng)默認(rèn)首頁(yè)首先加載時(shí)會(huì)導(dǎo)致viewPager的首頁(yè)第一次展示時(shí)沒(méi)有數(shù)據(jù)顯示,切換一下才會(huì)有數(shù)據(jù)。因?yàn)槭醉?yè)fragment的setUserVisible()在onActivityCreated() 之前調(diào)用,此時(shí)isPrepared為false 導(dǎo)致首頁(yè)fragment 沒(méi)能調(diào)用onLazyLoad()方法加載數(shù)據(jù)。

/**
 * 
 *     @author yangchong
 *     blog  : https://github.com/yangchong211
 *     time  : 2017/7/22
 *     desc  : 懶加載
 *     revise: 懶加載時(shí)機(jī):onCreateView()方法執(zhí)行完畢 + setUserVisibleHint()方法返回true

 */
public abstract class BaseLazyFragment extends BaseFragment {

    /*
     * 預(yù)加載頁(yè)面回調(diào)的生命周期流程:
     * setUserVisibleHint() -->onAttach() --> onCreate()-->onCreateView()-->
     *              onActivityCreate() --> onStart() --> onResume()
     */

    /**
     * 懶加載過(guò)
     */
    protected boolean isLazyLoaded = false;
    /**
     * Fragment的View加載完畢的標(biāo)記
     */
    private boolean isPrepared = false;

    /**
     * 第一步,改變isPrepared標(biāo)記
     * 當(dāng)onViewCreated()方法執(zhí)行時(shí),表明View已經(jīng)加載完畢,此時(shí)改變isPrepared標(biāo)記為true,并調(diào)用lazyLoad()方法
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        isPrepared = true;
        //只有Fragment onCreateView好了
        //另外這里調(diào)用一次lazyLoad()
        lazyLoad();
    }


    /**
     * 第二步
     * 此方法會(huì)在onCreateView()之前執(zhí)行
     * 當(dāng)viewPager中fragment改變可見(jiàn)狀態(tài)時(shí)也會(huì)調(diào)用
     * 當(dāng)fragment 從可見(jiàn)到不見(jiàn),或者從不可見(jiàn)切換到可見(jiàn),都會(huì)調(diào)用此方法
     * true表示當(dāng)前頁(yè)面可見(jiàn),false表示不可見(jiàn)
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        LogUtil.d("setUserVisibleHint---"+isVisibleToUser);
        //只有當(dāng)fragment可見(jiàn)時(shí),才進(jìn)行加載數(shù)據(jù)
        if (isVisibleToUser){
            lazyLoad();
        }
    }

    /**
     * 調(diào)用懶加載
     * 第三步:在lazyLoad()方法中進(jìn)行雙重標(biāo)記判斷,通過(guò)后即可進(jìn)行數(shù)據(jù)加載
     */
    private void lazyLoad() {
        if (getUserVisibleHint() && isPrepared && !isLazyLoaded) {
            showFirstLoading();
            onLazyLoad();
            isLazyLoaded = true;
        } else {
            //當(dāng)視圖已經(jīng)對(duì)用戶不可見(jiàn)并且加載過(guò)數(shù)據(jù),如果需要在切換到其他頁(yè)面時(shí)停止加載數(shù)據(jù),可以覆寫(xiě)此方法
            if (isLazyLoaded) {
                stopLoad();
            }
        }
    }

    /**
     * 視圖銷毀的時(shí)候講Fragment是否初始化的狀態(tài)變?yōu)閒alse
     */
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        isLazyLoaded = false;
        isPrepared = false;
    }

    /**
     * 第一次可見(jiàn)時(shí),操作該方法,可以用于showLoading操作,注意這個(gè)是全局加載loading
     */
    protected void showFirstLoading() {
        LogUtil.i("第一次可見(jiàn)時(shí)show全局loading");
    }

    /**
     * 停止加載
     * 當(dāng)視圖已經(jīng)對(duì)用戶不可見(jiàn)并且加載過(guò)數(shù)據(jù),但是沒(méi)有加載完,而只是加載loading。
     * 如果需要在切換到其他頁(yè)面時(shí)停止加載數(shù)據(jù),可以覆寫(xiě)此方法。
     * 存在問(wèn)題,如何停止加載網(wǎng)絡(luò)
     */
    protected void stopLoad(){

    }

    /**
     * 第四步:定義抽象方法onLazyLoad(),具體加載數(shù)據(jù)的工作,交給子類去完成
     */
    @UiThread
    protected abstract void onLazyLoad();
}
```

onLazyLoad()加載數(shù)據(jù)條件

getUserVisibleHint()會(huì)返回是否可見(jiàn)狀態(tài),這是fragment實(shí)現(xiàn)懶加載的關(guān)鍵,只有fragment 可見(jiàn)才會(huì)調(diào)用onLazyLoad() 加載數(shù)據(jù)。

isPrepared參數(shù)在系統(tǒng)調(diào)用onActivityCreated時(shí)設(shè)置為true,這時(shí)onCreateView方法已調(diào)用完畢(一般我們?cè)谶@方法里執(zhí)行findviewbyid等方法),確保 onLazyLoad()方法不會(huì)報(bào)空指針異常。

isLazyLoaded確保ViewPager來(lái)回切換時(shí)BaseFragment的initData方法不會(huì)被重復(fù)調(diào)用,onLazyLoad在該Fragment的整個(gè)生命周期只調(diào)用一次,第一次調(diào)用onLazyLoad()方法后馬上執(zhí)行 isLazyLoaded = true。

然后再繼承這個(gè)BaseLazyFragment實(shí)現(xiàn)onLazyLoad() 方法就行。他會(huì)自動(dòng)控制當(dāng)fragment 展現(xiàn)出來(lái)時(shí),才會(huì)加載數(shù)據(jù)

還有幾個(gè)細(xì)節(jié)需要優(yōu)化一下

當(dāng)視圖已經(jīng)對(duì)用戶不可見(jiàn)并且加載過(guò)數(shù)據(jù),如果需要在切換到其他頁(yè)面時(shí)停止加載數(shù)據(jù),可以覆寫(xiě)此方法,也就是stopLoad

視圖銷毀的時(shí)候講Fragment是否初始化的狀態(tài)變?yōu)閒alse,這個(gè)也需要處理一下

第一次可見(jiàn)時(shí),定義一個(gè)showFirstLoading方法,操作該方法,可以用于Loading加載操作,注意這個(gè)是全局加載loading,和下拉刷新數(shù)據(jù)或者局部刷新的loading不一樣的。可能有些開(kāi)發(fā)app,沒(méi)有將loading分的這么細(xì)。

07.懶加載配合狀態(tài)管理器

什么是狀態(tài)管理器?

一般在需要用戶等待的場(chǎng)景,顯示一個(gè)Loading動(dòng)畫(huà)可以讓用戶知道App正在加載數(shù)據(jù),而不是程序卡死,從而給用戶較好的使用體驗(yàn)。

當(dāng)加載的數(shù)據(jù)為空時(shí)顯示一個(gè)數(shù)據(jù)為空的視圖、在數(shù)據(jù)加載失敗時(shí)顯示加載失敗對(duì)應(yīng)的UI并支持點(diǎn)擊重試會(huì)比白屏的用戶體驗(yàn)更好一些。

加載中、加載失敗、空數(shù)據(jù)的UI風(fēng)格,一般來(lái)說(shuō)在App內(nèi)的所有頁(yè)面中需要保持一致,也就是需要做到全局統(tǒng)一。

如何降低偶性和入侵性

讓View狀態(tài)的切換和Activity徹底分離開(kāi),必須把這些狀態(tài)View都封裝到一個(gè)管理類中,然后暴露出幾個(gè)方法來(lái)實(shí)現(xiàn)View之間的切換。

在不同的項(xiàng)目中可以需要的View也不一樣,所以考慮把管理類設(shè)計(jì)成builder模式來(lái)自由的添加需要的狀態(tài)View。
- 那么如何降低耦合性,讓代碼入侵性低。方便維護(hù)和修改,且移植性強(qiáng)呢?大概具備這樣的條件……
    - 可以運(yùn)用在activity或者fragment中
    - 不需要在布局中添加LoadingView,而是統(tǒng)一管理不同狀態(tài)視圖,同時(shí)暴露對(duì)外設(shè)置自定義狀態(tài)視圖方法,方便UI特定頁(yè)面定制
    - 支持設(shè)置自定義不同狀態(tài)視圖,即使在BaseActivity統(tǒng)一處理狀態(tài)視圖管理,也支持單個(gè)頁(yè)面定制
    - 在加載視圖的時(shí)候像異常和空頁(yè)面能否用ViewStub代替,這樣減少繪制,只有等到出現(xiàn)異常和空頁(yè)面時(shí),才將視圖給inflate出來(lái)
    - 當(dāng)頁(yè)面出現(xiàn)網(wǎng)絡(luò)異常頁(yè)面,空頁(yè)面等,頁(yè)面會(huì)有交互事件,這時(shí)候可以設(shè)置點(diǎn)擊設(shè)置網(wǎng)絡(luò)或者點(diǎn)擊重新加載等等

那么具體怎么操作呢?

可以自由切換內(nèi)容,空數(shù)據(jù),異常錯(cuò)誤,加載,網(wǎng)絡(luò)錯(cuò)誤等5種狀態(tài)。父類BaseFragment直接暴露5中狀態(tài),方便子類統(tǒng)一管理狀態(tài)切換,這里fragment的封裝和activity差不多。

/**
 * 
 *     @author yangchong
 *     blog  : https://github.com/yangchong211
 *     time  : 2017/7/20
 *     desc  : fragment的父類
 *     revise: 注意,該類具有懶加載
 * 
*/ public abstract class BaseStateFragment extends BaseLazyFragment { protected StateLayoutManager statusLayoutManager; private View view; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { if(view==null){ view = inflater.inflate(R.layout.base_state_view, container , false); initStatusLayout(); initBaseView(view); } return view; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initView(view); initListener(); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } /** * 獲取到子布局 * @param view view */ private void initBaseView(View view) { LinearLayout llStateView = view.findViewById(R.id.ll_state_view); llStateView.addView(statusLayoutManager.getRootLayout()); } /** * 初始化狀態(tài)管理器相關(guān)操作 */ protected abstract void initStatusLayout(); /** * 初始化View的代碼寫(xiě)在這個(gè)方法中 * @param view view */ public abstract void initView(View view); /** * 初始化監(jiān)聽(tīng)器的代碼寫(xiě)在這個(gè)方法中 */ public abstract void initListener(); /** * 第一次可見(jiàn)狀態(tài)時(shí),showLoading操作,注意下拉刷新操作時(shí)不要用該全局loading */ @Override protected void showFirstLoading() { super.showFirstLoading(); showLoading(); } /*protected void initStatusLayout() { statusLayoutManager = StateLayoutManager.newBuilder(activity) .contentView(R.layout.common_fragment_list) .emptyDataView(R.layout.view_custom_empty_data) .errorView(R.layout.view_custom_data_error) .loadingView(R.layout.view_custom_loading_data) .netWorkErrorView(R.layout.view_custom_network_error) .build(); }*/ /*---------------------------------下面是狀態(tài)切換方法-----------------------------------------*/ /** * 加載成功 */ protected void showContent() { if (statusLayoutManager!=null){ statusLayoutManager.showContent(); } } /** * 加載無(wú)數(shù)據(jù) */ protected void showEmptyData() { if (statusLayoutManager!=null){ statusLayoutManager.showEmptyData(); } } /** * 加載異常 */ protected void showError() { if (statusLayoutManager!=null){ statusLayoutManager.showError(); } } /** * 加載網(wǎng)絡(luò)異常 */ protected void showNetWorkError() { if (statusLayoutManager!=null){ statusLayoutManager.showNetWorkError(); } } /** * 加載loading */ protected void showLoading() { if (statusLayoutManager!=null){ statusLayoutManager.showLoading(); } } } //如何切換狀態(tài)呢? showContent(); showEmptyData(); showError(); showLoading(); showNetWorkError(); //或者這樣操作也可以 statusLayoutManager.showLoading(); statusLayoutManager.showContent();

狀態(tài)管理器的設(shè)計(jì)思路

StateFrameLayout是繼承FrameLayout自定義布局,主要是存放不同的視圖,以及隱藏和展示視圖操作

StateLayoutManager是狀態(tài)管理器,主要是讓開(kāi)發(fā)者設(shè)置不同狀態(tài)視圖的view,以及切換視圖狀態(tài)操作

幾種異常狀態(tài)要用ViewStub,因?yàn)樵诮缑鏍顟B(tài)切換中l(wèi)oading和內(nèi)容View都是一直需要加載顯示的,但是其他的3個(gè)只有在沒(méi)數(shù)據(jù)或者網(wǎng)絡(luò)異常的情況下才會(huì)加載顯示,所以用ViewStub來(lái)加載他們可以提高性能。

OnRetryListener,為接口,主要是重試作用。比如加載失敗了,點(diǎn)擊視圖需要重新刷新接口,則可以用到這個(gè)。開(kāi)發(fā)者也可以自己設(shè)置點(diǎn)擊事件

關(guān)于狀態(tài)視圖切換方案,目前市場(chǎng)有多種做法,具體可以看我的這篇博客:https://juejin.im/post/5d2f01...

其他介紹 01.關(guān)于博客匯總鏈接

1.技術(shù)博客匯總

2.開(kāi)源項(xiàng)目匯總

3.生活博客匯總

4.喜馬拉雅音頻匯總

5.其他匯總

02.關(guān)于我的博客

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

簡(jiǎn)書(shū):http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜馬拉雅聽(tīng)書(shū):http://www.ximalaya.com/zhubo...

開(kāi)源中國(guó):https://my.oschina.net/zbj161...

泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...

郵箱:[email protected]

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault頭條:https://segmentfault.com/u/xi...

掘金:https://juejin.im/user/593943...

項(xiàng)目地址:https://github.com/yangchong2...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75578.html

相關(guān)文章

  • ViewPager2重大更新,支持offscreenPageLimit

    摘要:前言最近發(fā)布了版本,新增功能,該功能在上并不友好,現(xiàn)在官方將此功能延續(xù)下來(lái),這回是騾子是馬呢趕緊拉出來(lái)溜溜閱讀指南內(nèi)容基于版本講解,由于正式版還未發(fā)布,如有功能變動(dòng)有勞看官指出內(nèi)容重點(diǎn)介紹的特性和預(yù)加載機(jī)制,另外包括的狀態(tài)和的生命周前言 最近ViewPager2發(fā)布了1.0.0-alpha04版本,新增offscreenPageLimit功能,該功能在ViewPager上并不友好,現(xiàn)在官方將...

    番茄西紅柿 評(píng)論0 收藏0
  • PagerAdapter深度解析和實(shí)踐優(yōu)化

    摘要:如果是那么在初始狀態(tài)下,默認(rèn)會(huì)出現(xiàn)前兩個(gè)頁(yè)面,而主頁(yè)面是在的起始位置通常是屏幕左側(cè),直到最后一個(gè)頁(yè)面在屏幕右側(cè),如果總共個(gè)頁(yè)面,返回值為那么將一次性出現(xiàn)所有的頁(yè)面用于數(shù)據(jù)刷新時(shí)的頁(yè)面處理方式。 目錄介紹 01.PagerAdapter簡(jiǎn)單介紹02.PagerAdapter抽象方法03.PagerAdapter原理介紹04.PagerAdapter緩存和銷毀05.自定義PagerAdap...

    Paul_King 評(píng)論0 收藏0
  • Android基礎(chǔ):Fragment,看這篇就夠了

    摘要:也有類似的棧,稱為回退棧,回退棧是由管理的。為的參數(shù),通過(guò)能找到回退棧的特定元素,可以為或者,表示只彈出該元素以上的所有元素,表示彈出包含該元素及以上的所有元素。是異步執(zhí)行的,是丟到主線程的執(zhí)行,是同步版本。 歡迎大家前往云+社區(qū),獲取更多騰訊海量技術(shù)實(shí)踐干貨哦~ 由 天天P圖攻城獅 發(fā)布在云+社區(qū) 作者簡(jiǎn)介:damonxia(夏正冬),天天P圖Android工程師 下文中Demo的源...

    littleGrow 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<