Android中ViewPager+Fragment懶加載解決方案

文/程序員男神

前言

最近醫(yī)院上線,我們開發(fā)都奔赴醫(yī)院現(xiàn)場支持,每天加班到很晚射亏。自己也搞的精神不振罪裹,還好都把問題解決了。后面的幾天輕松了不少。本文就是最近在開發(fā)新需求遇到的問題,記錄下來以便后面供自己參考。


aj

問題描述

在android開發(fā)中徐绑,經(jīng)常會用到ViewPager+Fragment來實現(xiàn)切換Tab頁。但是莫辨,由于ViewPager的內(nèi)部機制傲茄,它總會默認至少預(yù)加載一個頁面。
因為有時候用戶希望選擇了哪個Tab再去加載哪個Tab的數(shù)據(jù)沮榜,而不是預(yù)加載盘榨,如果當前頁面和預(yù)加載頁面都需要實時刷新當前Fragment,或者有大量的網(wǎng)絡(luò)請求蟆融,可能就會比較慢草巡。

解決方案1:

ViewPager因為內(nèi)部機制,有預(yù)加載機制型酥。那我們直接把ViewPager的預(yù)加載設(shè)置為0不就可以了山憨?

vp.setOffscreenPageLimit(0);

查看源碼:

 /**
     * Set the number of pages that should be retained to either side of the
     * current page in the view hierarchy in an idle state. Pages beyond this
     * limit will be recreated from the adapter when needed.
     *
     * <p>This is offered as an optimization. If you know in advance the number
     * of pages you will need to support or have lazy-loading mechanisms in place
     * on your pages, tweaking this setting can have benefits in perceived smoothness
     * of paging animations and interaction. If you have a small number of pages (3-4)
     * that you can keep active all at once, less time will be spent in layout for
     * newly created view subtrees as the user pages back and forth.</p>
     *
     * <p>You should keep this limit low, especially if your pages have complex layouts.
     * This setting defaults to 1.</p>
     *
     * @param limit How many pages will be kept offscreen in an idle state.
     */
    public void setOffscreenPageLimit(int limit) {
        if (limit < DEFAULT_OFFSCREEN_PAGES) {
            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
                    + DEFAULT_OFFSCREEN_PAGES);
            limit = DEFAULT_OFFSCREEN_PAGES;
        }
        if (limit != mOffscreenPageLimit) {
            mOffscreenPageLimit = limit;
            populate();
        }
    }

我們分析得知:即使設(shè)置為0,也會把limit設(shè)置為默認值1弥喉。

解決方案2:

package com.winning.rims.tabtest.tst;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

/**
 * Fragment預(yù)加載問題的解決方案:
 * 1.可以懶加載的Fragment
 * 2.切換到其他頁面時停止加載數(shù)據(jù)(可選)
 * Created by dj on 2018-09-10.
 * blog :http://blog.csdn.net/linglongxin24/article/details/53205878
 */

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

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

    /**
     * 視圖是否已經(jīng)對用戶可見郁竟,系統(tǒng)的方法
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        isCanLoadData();
    }

    /**
     * 是否可以加載數(shù)據(jù)
     * 可以加載數(shù)據(jù)的條件:
     * 1.視圖已經(jīng)初始化
     * 2.視圖對用戶可見
     */
    private void isCanLoadData() {
        if (!isInit) {
            return;
        }
        if (getUserVisibleHint()) {
            lazyLoad();
            isLoad = true;
        } else {
            if (isLoad) {
                stopLoad();
            }
        }
    }

    /**
     * 視圖銷毀的時候講Fragment是否初始化的狀態(tài)變?yōu)閒alse
     */
    @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();
        }

    }

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

    /**
     * 獲取設(shè)置的布局
     *
     * @return
     */
    protected View getContentView() {
        return view;
    }

    /**
     * 找出對應(yīng)的控件
     *
     * @param id
     * @param <T>
     * @return
     */
    protected <T extends View> T findViewById(int id) {

        return (T) getContentView().findViewById(id);
    }

    /**
     * 當視圖初始化并且對用戶可見的時候去真正的加載數(shù)據(jù)
     */
    protected abstract void lazyLoad();

    /**
     * 當視圖已經(jīng)對用戶不可見并且加載過數(shù)據(jù),如果需要在切換到其他頁面時停止加載數(shù)據(jù)档桃,可以調(diào)用此方法
     */
    protected void stopLoad() {
    }
}

方案2的用法:

(1)枪孩、創(chuàng)建新的Fragment類,繼承BaseFragment藻肄;
(2)、setContentView()拒担,返回該xml布局文件嘹屯;
(3)、lazyLoad()从撼,在此方法內(nèi)加載需要的數(shù)據(jù)州弟;
(4)钧栖、stopLoad()方法可選,當視圖已經(jīng)對用戶不可見并且加載過數(shù)據(jù)婆翔,如果需要在切換到其他頁面時停止加載數(shù)據(jù)拯杠,可以覆寫此方法。

package com.winning.rims.tabtest.tst;

import android.util.Log;

import com.winning.rims.tabtest.R;

/**
 * 描述: Fragment1
 * 作者|時間: djj on 2018/9/11 16:14
 * 博客地址: http://www.reibang.com/u/dfbde65a03fc
 *
 */

public class Fragment1 extends BaseFragment {
    @Override
    public int setContentView() {
        return R.layout.fm_layout1;
    }

    @Override
    protected void lazyLoad() {
        String message = "Fragment1" + (isInit ? "已經(jīng)初始并已經(jīng)顯示給用戶可以加載數(shù)據(jù)" : "沒有初始化不能加載數(shù)據(jù)")+">>>>>>>>>>>>>>>>>>>";
        showToast(message);
        Log.d(TAG, message);
    }

    @Override
    protected void stopLoad() {
        Log.d(TAG, "Fragment1" + "已經(jīng)對用戶不可見啃奴,可以停止加載數(shù)據(jù)");
    }
}

fm_layout1 xmL布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textSize="22sp"
        android:textColor="@color/colorAccent"
        android:text="第一個Fragment" />

</LinearLayout>

其他Fragment一樣潭陪,不在此多舉例子。

activity 中的代碼實例:

package com.winning.rims.tabtest.tst;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.widget.RadioGroup;

import com.winning.rims.tabtest.R;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private RadioGroup rg;
    private ViewPager vp;

    private void assignViews() {
        rg = (RadioGroup) findViewById(R.id.rg);
        vp = (ViewPager) findViewById(R.id.vp);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);
        assignViews();
        initData();
    }

    private void initData() {
        final List<Fragment> fragments = new ArrayList<>();
        fragments.add(new Fragment1());
        fragments.add(new Fragment2());
        fragments.add(new Fragment3());
        fragments.add(new Fragment4());
        vp.setOffscreenPageLimit(0);
        vp.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return fragments.get(position);
            }

            @Override
            public int getCount() {
                return fragments.size();
            }
        });
        rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int i) {
                vp.setCurrentItem(radioGroup.indexOfChild(radioGroup.findViewById(i)));
            }
        });
    }
}

activity_main1 xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".tst.MainActivity">

    <RadioGroup
        android:id="@+id/rg"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:button="@null"
            android:gravity="center"
            android:text="第一個"
            android:textColor="#000000"
            android:textSize="18sp" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:button="@null"
            android:gravity="center"
            android:text="第二個"
            android:textColor="#000000"
            android:textSize="18sp" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:button="@null"
            android:gravity="center"
            android:text="第三個"
            android:textColor="#000000"
            android:textSize="18sp" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="1dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:button="@null"
            android:gravity="center"
            android:text="第四個"
            android:textColor="#000000"
            android:textSize="18sp" />
    </RadioGroup>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

日志

日志打印

通過查看日志最蕾,我們發(fā)現(xiàn)依溯,每次切換,都會先走stopLoad(),然后才去調(diào)用lazyLoad()方法瘟则。

總結(jié):
雖然參考到別人代碼黎炉,但是自己敲了一遍,還是很有收獲的醋拧,解決問題慷嗜,不需要焦頭爛額的思考的感覺真好。加油丹壕,真好洪添。哈哈哈...
參考代碼:https://blog.csdn.net/linglongxin24/article/details/53205878

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雀费,隨后出現(xiàn)的幾起案子干奢,更是在濱河造成了極大的恐慌,老刑警劉巖盏袄,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忿峻,死亡現(xiàn)場離奇詭異,居然都是意外死亡辕羽,警方通過查閱死者的電腦和手機逛尚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刁愿,“玉大人绰寞,你說我怎么就攤上這事∠晨冢” “怎么了滤钱?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長脑题。 經(jīng)常有香客問我件缸,道長,這世上最難降的妖魔是什么叔遂? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任他炊,我火速辦了婚禮争剿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘痊末。我一直安慰自己蚕苇,他們只是感情好,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布凿叠。 她就那樣靜靜地躺著涩笤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪幔嫂。 梳的紋絲不亂的頭發(fā)上辆它,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音履恩,去河邊找鬼锰茉。 笑死,一個胖子當著我的面吹牛切心,可吹牛的內(nèi)容都是我干的飒筑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼绽昏,長吁一口氣:“原來是場噩夢啊……” “哼协屡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起全谤,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤肤晓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后认然,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體补憾,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年卷员,在試婚紗的時候發(fā)現(xiàn)自己被綠了盈匾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡毕骡,死狀恐怖削饵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情未巫,我是刑警寧澤窿撬,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站橱赠,受9級特大地震影響尤仍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜狭姨,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一宰啦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饼拍,春花似錦赡模、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叨吮,卻和暖如春辆布,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背茶鉴。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工锋玲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涵叮。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓惭蹂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親割粮。 傳聞我的和親對象是個殘疾皇子盾碗,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

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