Android 懒加载优化

目录介绍

  • 1.什么是懒加载
    • 1.1 什么是预加载
    • 1.2 懒加载介绍
    • 1.3 懒加载概括
  • 2.实际应用中有哪些懒加载案例
    • 2.1 ViewPager+Fragment组合
    • 2.2 分析源码
  • 3.ViewPager中setOffscreenPageLimit(int limit)相关源码
  • 4.关于ViewPager与Fragment懒加载
    • 4.1 遇到的问题
    • 4.2 主要的思路做法
    • 4.3 代码案例展示
    • 4.4 onLazyLoad()加载数据条件
    • 4.5 Fragment的方法setUserVisibleHint
  • 5.懒加载Fragment为什么要继承BaseFragment

好消息

  • 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

1.什么是懒加载

  • 1.1 什么是预加载

    • ViewPager+Fragment的搭配在日常开发中也比较常见,可用于切换展示不同类别的页面,我们日常所见的咨询、购物、金融、社交等类型的APP都有机会用到这种控件组合
    • ViewPager控件有个特有的预加载机制,即默认情况下当前页面左右两侧的1个页面会被加载,以方便用户滑动切换到相邻的界面时,可以更加顺畅的显示出来。
    • 通过ViewPager的setOffscreenPageLimit(int limit)可以设置预加载页面数量,当前页面相邻的limit个页面会被预加载进内存
  • 1.2 懒加载介绍

    • 懒加载,其实也就是延迟加载,就是等到该页面的UI展示给用户时,再加载该页面的数据(从网络、数据库等),而不是依靠ViewPager预加载机制提前加载两三个,甚至更多页面的数据。这样可以提高所属Activity的初始化速度,也可以为用户节省流量.而这种懒加载的方式也已经/正在被诸多APP所采用。
    • 但是通过ViewPager方法setOffscreenPageLimit(int limit)的源码可以发现,ViewPager通过一定的逻辑判断来确保至少会预加载左右两侧相邻的1个页面,也就是说无法通过简单的配置做到懒加载的效果。
  • 1.3 懒加载概括

    • 当页面可见的时候,才加载当前页面。
    • 没有打开的页面,就不会预加载。
    • 说白了,懒加载就是可见的时候才去请求数据。

2.实际应用中有哪些懒加载案例

  • 1.1 ViewPager+Fragment的搭配使用懒加载
  • 1.2 H5网页使用懒加载

3.ViewPager中setOffscreenPageLimit(int limit)相关源码

  • 3.1 源码如下所示
//默认的缓存页面数量(常量)
private static final int DEFAULT_OFFSCREEN_PAGES = 1;

//缓存页面数量(变量)
private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;

public void setOffscreenPageLimit(int limit) {
    //当我们手动设置的limit数小于默认值1时,limit值会自动被赋值为默认值1(即DEFAULT_OFFSCREEN_PAGES)
    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) {
        //经过前面的拦截判断后,将limit的值设置给mOffscreenPageLimit,用于
        mOffscreenPageLimit = limit;
        populate();
    }
}
  • 3.2 分析源码可知
    • ViewPager通过一定的逻辑判断来确保至少会预加载左右两侧相邻的1个页面,也就是说无法通过简单的配置做到懒加载的效果。

4.关于ViewPager与Fragment懒加载

  • 4.1 遇到的问题

    • 在使用viewpager(或其他容器)与多个Fragment来组合使用,ViewPager 会默认一次加载当前页面前后隔一个页面,即使设置setofflimit(0)也无效果,也会预加载。这样把我们看不到的页面的数据也加载了,大大降低了性能,浪费初始化资源。然而我们就采用懒加载技术,只让用户看到的页面才会加载他的数据,大大提高效率。
  • 4.2 主要的思路做法

    • 主要的方法是Fragment中的setUserVisibleHint(),此方法会在onCreateView()之前执行,当viewPager中fragment改变可见状态时也会调用,当fragment 从可见到不见,或者从不可见切换到可见,都会调用此方法,使用getUserVisibleHint() 可以返回fragment是否可见状态。
    • 在BaseMVPLazyFragment中需要在onActivityCreated()及setUserVisibleHint()方法中都调了一次lazyLoad() 方法。如果仅仅在setUserVisibleHint()调用lazyLoad(),当默认首页首先加载时会导致viewPager的首页第一次展示时没有数据显示,切换一下才会有数据。因为首页fragment的setUserVisible()在onActivityCreated() 之前调用,此时isPrepared为false 导致首页fragment 没能调用onLazyLoad()方法加载数据。
  • 4.3 代码案例展示

public abstract class BaseMVPLazyFragment<T extends IBasePresenter> extends BaseMVPFragment<T> {
    /**
    * Fragment的View加载完毕的标记
    */
    protected boolean isViewInitiated;
    /**
    * Fragment对用户可见的标记
    */
    protected boolean isVisibleToUser;
    /**
    * 是否懒加载
    */
    protected boolean isDataInitiated;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    /**
    * 第一步,改变isViewInitiated标记
    * 当onViewCreated()方法执行时,表明View已经加载完毕,此时改变isViewInitiated标记为true,并调用lazyLoad()方法
    */
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        isViewInitiated = true;
        //只有Fragment onCreateView好了,
        //另外这里调用一次lazyLoad()
        prepareFetchData();
        //lazyLoad();
    }

    /**
    * 第二步
    * 此方法会在onCreateView()之前执行
    * 当viewPager中fragment改变可见状态时也会调用
    * 当fragment 从可见到不见,或者从不可见切换到可见,都会调用此方法
    */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        prepareFetchData();
    }

    /**
    * 第四步:定义抽象方法fetchData(),具体加载数据的工作,交给子类去完成
    */
    public abstract void fetchData();

    /**
    * 第三步:在lazyLoad()方法中进行双重标记判断,通过后即可进行数据加载
    * 第一种方法
    * 调用懒加载,getUserVisibleHint()会返回是否可见状态
    * 这是fragment实现懒加载的关键,只有fragment 可见才会调用onLazyLoad() 加载数据
    */
    private void lazyLoad() {
        if (getUserVisibleHint() && isViewInitiated && !isDataInitiated) {
            fetchData();
            isDataInitiated = true;
        }
    }

    /**
    * 第二种方法
    * 调用懒加载
    */
    public void prepareFetchData() {
        prepareFetchData(false);
    }

    /**
    * 第三步:在lazyLoad()方法中进行双重标记判断,通过后即可进行数据加载
    */
    public void prepareFetchData(boolean forceUpdate) {
        if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
            fetchData();
            isDataInitiated = true;
        }
    }
}
  • 4.4 onLazyLoad()加载数据条件

    • getUserVisibleHint()会返回是否可见状态,这是fragment实现懒加载的关键,只有fragment 可见才会调用onLazyLoad() 加载数据。
    • isPrepared参数在系统调用onActivityCreated时设置为true,这时onCreateView方法已调用完毕(一般我们在这方法里执行findviewbyid等方法),确保 onLazyLoad()方法不会报空指针异常。
    • isLazyLoaded确保ViewPager来回切换时BaseFragment的initData方法不会被重复调用,onLazyLoad在该Fragment的整个生命周期只调用一次,第一次调用onLazyLoad()方法后马上执行 isLazyLoaded = true。
    • 然后再继承这个BaseMVPLazyFragment实现onLazyLoad() 方法就行。他会自动控制当fragment 展现出来时,才会加载数据
  • 4.5 Fragment的方法setUserVisibleHint

    • 源码如下所示
    • image
    • 通过此方法来设置Fragment的UI对用户是否可见,当该页面对用户可见/不可见时,系统都会回调此方法。
    • 我们可以重写此方法,然后根据回调的isVisibleToUser参数来进行相关的逻辑判断,以达到懒加载的效果,比如如果isVisibleToUser==true的话表示当前Fragment对用户可见,此时再去加载页面数据。

5.懒加载Fragment为什么要继承BaseFragment

  • 5.1 继承BaseFragment好处
    • 这个BaseFragment就是最基础的基类了,里面进行一些最底层的设置,定义抽象函数:比如布局文件的绑定,初始化视图控件,初始化数据,初始化Toolbar
    • 所以这个懒加载LazyLoadFragment基本上是隔离开了。耦合度相当低,基本都可以这样使用吧。
    • 还有一点,有些Fragment不需要懒加载,那么可以直接继承BaseFragment类;需要懒加载的直接继承BaseMVPLazyFragment类

6.关于我的个人博客和站点

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

推荐阅读更多精彩内容