Fragment懒加载实现

昨天写代码的时候发现项目里面的订单页面重新载入数据的时候会出现多次添加,检查了下代码才发现原来是懒加载出的问题。本来准备偷一下懒的,但是网上一直没找到满意的(p.s 主要还是我自个有点强迫症 (。・ω・。) ),所以还是自己写一个备忘吧。如果只是需要代码的话,可以滑动到最下面copy一下,忽略我的思路。


一. Fragment懒加载定义

说到Fragment懒加载,顾名思义就是让Fragment在不显示的时候不预加载数据。可能初学者会不理解,“Fragment不显示?难道是创建的时候?”,不是的,Fragment的显示隐藏状态是Fragment创建之后的一个状态,这个状态根据片段是否调用了setUserVisibleHint()方法而变化。通过查询源码,我们可以发现他是PagerAdapter对象调用的。这意味着只有使用PagerAdapter或者它的子类作为适配器的ViewPager才会触发这个方法。那么Fragment懒加载也只是针对ViewPager了,而不能用到add()hide()方法里。

image

二. Fragment懒加载的思路

通过懒加载的定义,大概可以了解到实现懒加载的关键在setUserVisibleHint()方法,那么是不是可以在这个方法里面直接判断是否显示然后调用数据加载呢?但是调用日志打印,却发现ViewPager加载的Fragment一开始就调用了setUserVisibleHint()方法,而且还是调用了多次。

E/打印: pagerNum = 0 setUserVisibleHint() + false
E/打印: pagerNum = 0 setUserVisibleHint() + false
E/打印: pagerNum = 0 setUserVisibleHint() + true
E/打印: pagerNum = 0 onCreate pagerNum = 0 onCreate()
E/打印: pagerNum = 0 onCreateView()
E/打印: pagerNum = 0 onActivityCreated()

那么,从打印出来的日志看,ViewPager + Fragment运行后,Fragment先运行了setUserVisibleHint(),然后再走了视图创建。那么上面说的在这个方法里面直接判断并懒加载是会出问题的。那么就做个变量判断,如果显示了并且视图创建了,那么就懒加载。


@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (getUserVisibleHint()) {
        isVisible = true;
        if (isPrepared && isVisible) {
            lazyLoad();
        }
    } else {
        isVisible = false;
        onInvisibleLoad();
    }
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    isPrepared = true;
    if (isPrepared && isVisible) {
        lazyLoad();
    }
}

public abstract void lazyLoad() ;

但是,这样真就可以了嘛?我试了一下多个Fragment作为ViewPager的嵌套。

image

E/打印: pagerNum = 0 setUserVisibleHint() isVisibleToUser = false
E/打印: pagerNum = 0 setUserVisibleHint() isVisibleToUser = false
E/打印: pagerNum = 0 setUserVisibleHint() isVisibleToUser = true
E/打印: pagerNum = 0 onActivityCreated() time = 1552032454259
E/打印: pagerNum = 0 lazyLoad()
E/打印: pagerNum = 1 onActivityCreated() time = 1552032454277
E/打印: pagerNum = 0 setUserVisibleHint() isVisibleToUser = false
E/打印: pagerNum = 0 setUserVisibleHint() isVisibleToUser = false
E/打印: pagerNum = 0 setUserVisibleHint() isVisibleToUser = true
E/打印: pagerNum = 4 onActivityCreated() time = 1552032460733
E/打印: pagerNum = 4 lazyLoad()
E/打印: pagerNum = 3 onActivityCreated() time = 1552032460742
E/打印: pagerNum = 5 onActivityCreated() time = 1552032460750
E/打印: pagerNum = 0 setUserVisibleHint() isVisibleToUser = false
E/打印: pagerNum = 1 setUserVisibleHint() isVisibleToUser = false
E/打印: pagerNum = 4 setUserVisibleHint() isVisibleToUser = false
E/打印: pagerNum = 0 setUserVisibleHint() isVisibleToUser = true
E/打印: pagerNum = 0 lazyLoad()
E/打印: pagerNum = 0 onActivityCreated() time = 1552032470357
E/打印: pagerNum = 0 lazyLoad()
E/打印: pagerNum = 1 onActivityCreated() time = 1552032470359

然后就发现了,点击了标题4或者5,再重新点回标题1的时候,lazyLoad()加载了两次。这就是为什么我昨天遇到的,明明清空了数据,结果,他跨格切页会重复添加数据。因为onCreateView()方法的多次请求,即使调用了清空数据,但是由于网络请求的延时,造成数据的重复添加。

(懒得画图了,这里贴上大神制作的流程图,上面是关于多ViewPager嵌套的。)

image
image

然后,从算法逻辑考虑,这是懒加载它不够“懒”造成的。所以改进一下,并且按照MVP原则,可以写成一个基本懒加载片段类。


import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
* ========================================
*
* @author ydw
* Create on 2019/3/7
* 描述: 懒加载基本页面 
* =========================================
*/

public abstract class BaseLazyFragment extends Fragment {

    protected boolean isVisible;
    private boolean isPrepared = false, isInitial = false ;
    private View mRootView;
    public FragmentActivity act;
    public BasicFragment fragment = this;
    private boolean isFirst = true;

    public BaseLazyFragment () {
        // Required empty public constructor
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        act = getActivity();
        setHasOptionsMenu(true); //设置片段可以使用菜单栏
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (getUserVisibleHint()) {
            isVisible = true;
            lazyLoad();
        } else {
            isVisible = false;
            onInvisibleLoad();
        }
    }

    @Override
    public void onActivityCreated(@Nullable Bundle 
 savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (!isInitial) {
            initData();
            isInitial = true;
        }

        if (!isPrepared) {
            isPrepared = true;
            lazyLoad();
        }
    }

    private void lazyLoad() {
        if (!isPrepared || !isVisible) {
            return;
        }

        if (isFirst) {
            isFirst = false;
            onVisibleLoad(true);

        } else {
            onVisibleLoad(false);
        }
    }

    //页面显示的时候进行动作
    public void onVisibleLoad(boolean isFirst){
        //do something
    }

    //页面隐藏的时候进行动作
    public void onInvisibleLoad() {
        //do something
    }

    public boolean isFirst() {
        return isFirst;
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        if (mRootView == null) {
            mRootView = initView(inflater, container, savedInstanceState);
        }

         return mRootView;
    }

    public View getRootView() {
        return mRootView;
    }

    public abstract View initView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);

    public abstract void initData();

}

(p.s 本来这个页面没这么多,我是拆分成很多个基本类的,但是这里为了方便查看,就都放一起了。)

写到这里突然发现,今天居然是个节日哈,那顺便祝福各位女王节日快乐~


每多走一步,就与梦想更近一步。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容