一篇文章搞定《ViewPage2离屏加载》

news2024/12/24 9:13:34

------《ViewPage2离屏加载》

  • 前言
  • 离屏加载是什么
  • OffscreenPageLimit
  • 设置OffscreenPageLimit表现
    • OffscreenPageLimit值为1
    • OffscreenPageLimit值为3
  • OffscreenPageLimit值取多大比较合适

前言

这里就不讲ViewPage了,买新不买旧,用新不用旧。
但是会将ViewPage和ViewPage2进行对比一下。
ViewPage2是基于RecyclerView进行处理的。所以他也继承了RecyclerView的缓存和预加载机制。
为了看清离屏加载的机制,可以先关闭一下预加载。

((RecyclerView)viewPager.getChildAt(0)).getLayoutManager().setItemPrefetchEnabled(false);

离屏加载是什么

离屏加载最主要的控制参数:OffscreenPageLimit
该值代表的是在滑动视图中应保留在当前可见页面之外的任一方向上的页面数。
比如,当我们采用水平分页时,该值代表的便是在左右两侧应保留的页面数。
在这里插入图片描述
而当我们采用垂直分页时,该值代表的则是在上下两侧应保留的页面数。
在这里插入图片描述
保留页面的方式是通过扩展额外的布局空间实现的,以LinearLayoutManager为例,其最关键的步骤在于对calculateExtraLayoutSpace方法的重写:

/**
    * 计算额外的布局空间
    */
    @Override
    protected void calculateExtraLayoutSpace(@NonNull RecyclerView.State state,
            @NonNull int[] extraLayoutSpace) {
        int pageLimit = getOffscreenPageLimit();
        if (pageLimit == OFFSCREEN_PAGE_LIMIT_DEFAULT) {
            // 仅在需要时才对屏幕外页面进行自定义预取
            super.calculateExtraLayoutSpace(state, extraLayoutSpace);
            return;
        }
        // 计算多pageLimit*2个页面大小的空间
        final int offscreenSpace = getPageSize() * pageLimit;
        extraLayoutSpace[0] = offscreenSpace;
        extraLayoutSpace[1] = offscreenSpace;
    }
    
    /**
    * 获取单个页面大小
    */
    int getPageSize() {
        final RecyclerView rv = mRecyclerView;
        // 水平分页时,取去除了左右内边距后的RecyclerView宽度
        // 垂直分页时,取去除了上下内边距后的RecyclerView高度
        return getOrientation() == ORIENTATION_HORIZONTAL
                ? rv.getWidth() - rv.getPaddingLeft() - rv.getPaddingRight()
                : rv.getHeight() - rv.getPaddingTop() - rv.getPaddingBottom();
    }

该方法会计算LinearLayoutManager应布置的额外空间量(以像素为单位)。已知默认布置的空间量为单个页面大小,则额外布置的空间量应为OffscreenPageLimit*2个单页面大小,计算出来的结果会存储在int数组类型的extraLayoutSpace结构中,其中:

  • extraLayoutSpace[0]应用于顶部或左侧的额外空间;
  • extraLayoutSpace[1]应用于底部或右侧的额外空间。

虽然这部分额外创建的页面在当前屏幕上并不可见,但实际已经被添加至我们的视图层次结构中了。这么做可以减少切换分页时花费在视图创建与布局上的时间,从而提升ViewPager2滑动时的整体流畅度。
结合前面两篇文章我们可以看到,从缓存复用机制到预拉取机制再到现在的离屏加载机制,RecyclerView与ViewPager2在提升滑动流畅度方面真的是做了非常多的努力。
区别在于:

  • 缓存复用机制是通过缓存已创建的页面,以提供给新进入屏幕的页面重用来实现的。
  • 预拉取机制是通过利用UI线程空闲的时机,提前创建并缓存下一个待进入屏幕的页面来实现的。
  • 离屏加载机制则是通过扩展额外的布局空间,以提前创建并保留屏幕两侧的页面来实现的。

从调用方法流程上讲,离屏加载机制除了常规的onCreateViewHolder、onBindViewHolder方法之外,还会执行一个多onViewAttachedToWindow方法,以将页面提前添加至我们的视图层次结构中。

OffscreenPageLimit

ViewPager一直为人所诟病的一个点就是,其设置的OffscreenPageLimit默认值为1,且不允许外部传入低于1的修改值,即会「强制开启离屏加载机制」。
这也就意味着,在使用ViewPager构建的滑动视图中,不管开发者需不需要,都至少会有1~2个页面会被离屏加载,而这会导致一系列依赖于Fragment生命周期的逻辑被异常执行,进而产生非预期的结果,需要开发者手动实现延迟加载机制。
相比较之下,ViewPager2设置的OffscreenPageLimit默认值则为-1,也即「默认不开启离屏加载机制
这种情况下只有RecyclerView的缓存复用机制和预拉取机制会工作。

public static final int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1;

且对于外部传入的修改值可以为大于1的整数。

public void setOffscreenPageLimit(@OffscreenPageLimit int limit) {
    if (limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT) {
        throw new IllegalArgumentException(
                "Offscreen page limit must be OFFSCREEN_PAGE_LIMIT_DEFAULT or a number > 0");
    }
    mOffscreenPageLimit = limit;
    // Trigger layout so prefetch happens through getExtraLayoutSize()
    mRecyclerView.requestLayout();
}

另外,ViewPager2是在RecyclerView的基础上构建而成的。因此,即使是默认不开启离屏加载机制,预拉取机制也会正常工作。
但实际情况是,大部分的开发者为图方便,往往会将此值设为「页面总数-1」,也就是缓存所有的页面。但是这是不规范的。

设置OffscreenPageLimit表现

OffscreenPageLimit值为1

当OffscreenPageLimit值为1时,也即会在左右两侧各离屏加载1个页面。
在这里插入图片描述
1、当滑动视图初始化完成时,由于左侧无更多的页面项,因此只有position=0及position=1的页面项会被添加至当前视图层次结构中。
2、随着我们往左滑动屏幕,position=2的页面项会被添加至当前视图层次结构中,而position=0的页面项会继续保留在当前视图层次结构中,同时预拉取机制会开始工作,提前创建position=3的页面项并放入mCachedView中。
在这里插入图片描述
3、再次向左滑动屏幕,滑动视图会取出预拉取的position=3的页面项添加至当前视图层次结构中,而position=1的页面项会继续保留在当前视图层次结构中,并开启对position=4的页面项的预拉取。
4、同时,position=0的页面项也将随着向左滑动的手势被移出屏幕,并放入mCachedView中
在这里插入图片描述
5、第三次向左滑动屏幕,同样,会取出预拉取的position=4的页面项添加至当前视图层次结构中,并保留position=2的页面项在当前视图层次结构中,同时开启对position=5的页面项的预拉取。
6、此时,由于还未超过mCachedView大小的限制,下一个被移出屏幕的position=1的页面项也将放入mCachedView中。
在这里插入图片描述
7、第四次向左滑动屏幕,同样,会取出预拉取的position=5的页面项添加至当前视图层次结构中,并保留position=3的页面项在当前视图层次结构中,同时开启对position=6的页面项的预拉取。
8、但是,由于超过了mCachedView大小的限制,在下一个被移出屏幕的position=2的页面项尝试进入时,会先按照先进先出的顺序,先从mCachedView中移出position=0的页面项,放入RecyclerPool中对应itemType的ArrayList容器中。

OffscreenPageLimit值为3

当OffscreenPageLimit值为3时,也即会在左右两侧各离屏加载3个页面。
在这里插入图片描述
1、当滑动视图初始化完成时,由于左侧无更多的页面项,因此只有position=0至position=3的页面项会被添加至当前视图层次结构中。
2、随着我们往左滑动屏幕,position=4的页面项会被添加至当前视图层次结构中,而position=0的页面项会继续保留在当前视图层次结构中,同时预拉取机制会开始工作,提前创建position=5的页面项并放入mCachedView中。
在这里插入图片描述
3、再次向左滑动屏幕,滑动视图会取出预拉取的position=5的页面项添加至当前视图层次结构中,而position=1的页面项会继续保留在当前视图层次结构中,并开启对position=6的页面项的预拉取。
缓存全部的页面的话就设置OffscreenPageLimit为页面的总数 - 1即可。

OffscreenPageLimit值取多大比较合适

当OffscreenPageLimit值设得过大,会给应用带来比较大的内存压力,特别是在部分低端机型上。
而OffscreenPageLimit值设得过小,比如1时,又无法发挥出离屏加载机制提高页面滑动流畅度的优势。
一般来讲,同时保持3-4个页面项处于活动状态是一个比较合适的值,一方面,可以提高用户来回翻页时的流畅度,另一方面又不会给应用带来太大的内存压力。当然,还需要我们自己维护好Fragment重建以及视图回收/复用时的处理逻辑。
最好的情况下,还是希望能够根据应用当前的内存使用情况,对该值进行动态调整,在行为表现与性能影响上取一个平衡点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/508644.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Power BI: 表格显示切片器选中时间之前的数据

例如下面的例子&#xff0c;Year List表和Caleadar表是1对多的关联关系。 Caleadar表&#xff1a; Caleadar VAR StartYear YEAR(NOW())-5 VAR EndYear YEAR(NOW())5 RETURN ADDCOLUMNS (CALENDAR (DATE(StartYear,1,1), DATE(EndYear,12,31)),"Year", YEAR ([…

【设计模式】| 修炼内功 | 23种设计模式——工厂方法模式(含抽象)

设计模式如同织锦之艺术&#xff0c;精心构筑&#xff0c;展示优美。 学习设计模式&#xff0c;犹如追逐清晨的曙光&#xff0c;扉页掀开了人生的新篇章。当你学会设计模式的奥秘&#xff0c;就如同走进了灯火通明的城市&#xff0c;丰富多彩的建筑&#xff0c;让你大开眼界&am…

30个最常用的空间SQL用例

在开始使用空间 SQL 时&#xff0c;至少对我而言&#xff0c;最大的挑战之一是拥有一个快速简便的参考&#xff0c;以将你当前的 GIS 工作流转换为 SQL。 有许多令人惊叹的资源可以扩展这方面的知识&#xff0c;但本指南旨在成为一本真正简单的食谱&#xff0c;以开始将你当前的…

从零开始的强化学习入门学习路线

强化学习是机器学习领域中的一个分支&#xff0c;它是指智能体通过与环境的交互来学习如何采取最佳行动以最大化奖励信号的过程。强化学习在许多领域都有广泛的应用&#xff0c;如游戏、自动驾驶和机器人控制等。如果你对强化学习感兴趣&#xff0c;下面是一个入门强化学习的学…

SequoiaDB分布式数据库2023.4月刊

本月看点速览 赋能产业升级&#xff0c;荣获新睿之星 聚焦金融&#xff0c;进一步探索非结构化数据价值释放 再获肯定&#xff0c;入选2023年中国最佳信创厂商入围名单 青杉计划2023已开启&#xff0c;一起攀登更高的“杉” 赋能产业升级&#xff0c;荣获新睿之星 4月18日…

PyTorch典型函数之gather

PyTorch典型函数之gather 作用描述函数详解典型应用场景(1) 深度强化学习中计算损失函数 参考链接 作用描述 如上图所示&#xff0c;假如我们有一个Tensor A&#xff08;图左&#xff09;&#xff0c;要从A中提取一部分元素组成Tensor B&#xff08;图右&#xff09;&#xff0…

7.外观模式C++用法示例

外观模式 一.外观模式1.原理2.特点3.外观模式与装饰器模式的异同4.应用场景C程序示例 一.外观模式 外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它提供了一个简单的接口&#xff0c;隐藏了一个或多个复杂的子系统的复杂性&#xff0c;并使…

图嵌入表示学习—Node Embeddings随机游走

Random Walk Approaches for Node Embeddings 一、随机游走基本概念 想象一个醉汉在图中随机的行走&#xff0c;其中走过的节点路径就是一个随机游走序列。 随机行走可以采取不同的策略&#xff0c;如行走的方向、每次行走的长度等。 二、图机器学习与NLP的关系 从图与NLP的…

posix线程的优先级测试

如果创建的线程不够多&#xff0c;有些问题是体现不出来的。 优先级打印&#xff1a; 测试目的&#xff1a;输出三种调度模式下的最大优先级和最小优先级 #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <fcntl.h> #…

Kubernetes_容器网络_01_Docker网络原理(二)

文章目录 一、前言二、被隔离的Docker容器三、网桥Bridge四、VethPair网络对五、统一宿主机上的两个Container容器通信六、宿主机访问其上的容器七、宿主机上的容器访问另一个宿主机八、尾声 一、前言 二、被隔离的Docker容器 Linux 网络&#xff0c;就包括&#xff1a;网卡&…

技术选型对比- RPC(Feign VS Dubbo)

协议 Dubbo 支持多传输协议: Dubbo、Rmi、http,可灵活配置。默认的Dubbo协议&#xff1a;利用Netty&#xff0c;TCP传输&#xff0c;单一、异步、长连接&#xff0c;适合数据量小(传送数据小&#xff0c;不然影响带宽&#xff0c;响应速度)、高并发和服务提供者远远少于消费者…

UnityWebGL+阿里云服务器+Apache完成项目搭建展示

一、服务器相关 Step1:租借一台阿里云服务器 我自己租借了一台北京的ECS服务器&#xff0c;有免费一年的活动&#xff0c;1 vCPU 2 GiB&#xff0c;我自己选择的Ubuntu系统&#xff0c;也可以选择Windows系统 Step2:进入远程连接 进入自己的服务器实例后&#xff0c;点击远程…

vue+elementui+nodejs机票航空飞机航班查询与推荐

语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;VScode )本系统主要是为旅客提供更为便利的机票预定方式&#xff0c;同时提高民航的预定机票的工作效率。通过网络平台实现信息化和网络化&am…

关于Android的性能优化,主要是针对哪些方面的问题进行优化

前言 我们在开发Android的时候&#xff0c;经常会遇到一些性能问题&#xff1b;例如&#xff1a;卡顿、无响应&#xff0c;崩溃等&#xff0c;当然&#xff0c;这些问题为我们可以从日志来进行追踪&#xff0c;尽可能避免此类问题的发生&#xff0c;要解决这些问题&#xff0c…

mysql从零开始(05)----锁

全局锁 使用 # 启用全局锁 flush tables with read lock # 释放全局锁 unlock tables开启全局锁后&#xff0c;整个数据库就处于只读状态了&#xff0c;这种状态下&#xff0c;对数据的增删改操作、对表结构的更改操作都会被阻塞。 另外&#xff0c;当会话断开&#xff0c;全…

【1015. 可被 K 整除的最小整数】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给定正整数 k &#xff0c;你需要找出可以被 k 整除的、仅包含数字 1 的最 小 正整数 n 的长度。 返回 n 的长度。如果不存在这样的 n &#xff0c;就返回 -1。 注意&#xff1a; n 不符合 64 位带…

手把手教你在winform中将文本或文件路径拖到控件中

文章目录 前言博主履历介绍&#xff1a;一、将txt文件的所有内容复制到 RichTextBox中二、将txt文件的一行内容移动到RichTextBox中三、将多个文件的全路径复制到 RichTextBox中四 、源码1、[Winform从入门到精通&#xff08;1&#xff09;——&#xff08;如何年入30万&#x…

「MIAOYUN」:降本增效,赋能传统企业数字化云原生转型 | 36kr 项目精选

作为新经济综合服务平台第一品牌&#xff0c;36氪自2019年落地四川站以来&#xff0c;不断通过新锐、深度的商业报道&#xff0c;陪跑、支持四川的新经济产业。通过挖掘本土优质项目&#xff0c;36氪四川帮助企业链接更多资源&#xff0c;助力企业成长&#xff0c;促进行业发展…

分布式系统概念和设计——命名服务设计和落地经验

分布式系统概念和设计 通过命名服务&#xff0c;客户进程可以根据名字获取资源或对象的地址等属性。 被命名的实体可以是多种类型&#xff0c;并且可由不同的服务管理。 命名服务 命名是一个分布式系统中的非常基础的问题&#xff0c;名字在分布式系统中代表了广泛的资源&#…

C语言:指针求解鸡兔同笼问题

题目&#xff1a;鸡兔同笼问题 要求&#xff1a;使用自定义函数void calc(int h, int f,int *c,int *r) 求解鸡兔同笼问题。 h 表示总的头数&#xff0c;f 表示总的脚数。 例子&#xff1a; 输入&#xff1a; 5 16 输出&#xff1a; 2 3 分析&#xff1a; 在该代码中&a…