RecyclerView Prefetch功能探究

在Android的开发中,滚动列表是一个出镜率非常高的组件。这其中RecyclerView是当然不让的明星。从Native到weex,RecyclerView有着非常广泛的使用。正因如此,我们持续不断地针对RecyclerView页面进行优化。在最近一次调研RecyclerView优化的过程中,偶然看到google在最新版版本的RecyclerView中增加了Prefetch功能。Prefetch的功能到底做了哪些事情,是不是真的能提升页面性能,使用的成本有多高?

针对这些问题,本文将分三步来做一个简单的探究:

  • (1)功能怎么用
  • (2)效果怎么样
  • (3)原理是什么

1. Prefetch功能的使用

在研究Prefetch功能的实际效果之前,首先需要能正常使用Prefetch功能。

  • 第一步 :升级 Support Library的版本到 25.3.1

    google官方在 Support Library v25 版本中,为RecyclerView增加了Prefetch。
    并且在 v25.1.0 以及25.3.0版本中进行了完善。在最新的稳定版本25.3.1中已经基本稳定。
    如果需要使用建议升级到25.3.1版本。详细可见support-library change log

    注意: android support v4 包从24.2.0版本开始拆分成了多个更小的模块。

    包括:support-compat,support-core-utils,support-core-ui,support-media-compat以及
    support-fragment。如果出现使用

    compile group: 'com.android.support', name: 'support-v4',
    version: '25.3.1', ext: 'jar'
    

    出现了类找不到的情况,需要按照需要依赖上述子包。

  • 第二步:实现LayoutManager
    • 如果你使用的是官方的LayoutManager,那么直接可以获取Prefetch的功能,无需任何其他的定制。
    • 但是如果你使用的是自定义的LayoutManager,需要重写LayoutManager.collectAdjacentPrefetchPositions()
      方法。如果嵌套RecyclerView使用需要复写setInitialPrefetchItemCount
      详细信息可以参见具体的API文档(点击直接跳转)
    • 第三步:设置打开Prefetch

    默认情况下Prefetch的功能是打开的。当然也可以手动选择关闭:

    LayoutManager.setItemPrefetchEnabled(false);
    

    所以确认一下不要手动关闭预取功能

    在完成上述三个步骤以后,可以像往常一样使用RecyclerView,并且自带了prefetch功能。

2.Prefetch实际效果

RecyclerView的Prefetch功能正常运转以后。那么这个功能到底能带来多少性能的收益是现在需要确认的。分几个部分来看:

demo
  • demo内容:
    使用Android官方提供的StaggeredGridLayoutManager实现了一个瀑布流。
    瀑布流中文字的数量和图片的大小都是可以变的。展示如下:

衡量标准&方法:
  • GPU呈现模式分析 打开的GPU渲染条形图。图中的绿线是流畅度的分割线。超过绿线的帧都是渲染超时的。比较的核心指标是滑动过程中,超出绿线frame占比。

    (注:流畅的标准是1s 60帧 一帧的渲染时间大约是16ms)
    
  • 测试设备小米5s
  • 数据绑定复杂度模拟:
    为了检测预取功能在不同的页面渲染复杂度情况下的实际效果。在RecyclerView数据绑定函数:onBindViewHolder函数中,使用

    Thread.sleep(time);
    

    来模拟页面渲染的复杂度。复杂度的大小,通过time时间的长短来体现。时间越长,复杂度越高。

原始demo流畅度对比
打开prefetch 关闭prefetch

在原始demo中,由于复杂度有限,无论是打开或者关闭prefetch功能,滑动过程中无明显差异。

延时8ms 流畅度对比
打开prefetch 关闭prefetch

通过延时8ms,整个数据绑定的复杂度急剧上升。在关闭prefetch功能的情况下,在16ms 内无法完成的渲染的帧数明显增多。相比之下打开prefetch以后,页面依然非常流畅。

延时12ms 流畅度对比
打开prefetch 关闭prefetch

通过延时12ms在关闭prefetch功能的情况下,在16ms 内无法完成的渲染的帧数进一步增多,页面卡顿愈加明显。但是打开prefetch以后,页面依然非常流畅。

延时17ms 流畅度对比
打开prefetch 关闭prefetch

通过延时17ms,在16ms时间内完成渲染已经无法做到。滑动过程中,滑动卡顿可以明显被感知。在关闭prefetch功能的情况下,在16ms内无法完成的渲染的帧数进一步增多,并且延时也更长。打开prefetch以后,同样不可避免的会出现16ms无法渲染帧,但是页面对比下还是更加流畅。

结论:基于上述实验,可以得出以下几个结论:
  1. 使用prefetch以后,recyclerView的流畅度对页面复杂度的敏感性降低。
  2. 在高复杂度(recyclerView的子项view的创建和绑定更加耗时)情况下,prefetch功能确实能显著提高页面流畅度。

3.Prefetch原理:

android 5.0以后,android系统为了提高UI渲染的效率引入了RenderThread。通过这样的设计,将主线程从UI
渲染的繁重工作中解脱出来。在UI渲染过程中,主线程可以更加专注于跟用户进行交互。这样可以大大提高页面流畅度。
通过Systrace工具跟踪一个页面,获取页面渲染详细数据。

  注意:如果使用DDMS来抓取。一定要记得在Enable Application Traces from 中选择APP所在的进程。否则你可能无法观察到Prefetch的渲染。如下图所示:

一个常规页面的渲染流程如下:

通过上面的展示,UI线程准备页面数据并且在ready以后交由Render线程渲染。帧与帧之间通过帧同步信号sync来同步。如果页面渲染无法在规定时间内完成,就会出现丢帧情况渲染的时序会变成如下情况:

不难发现在正常渲染过程中,有一个非常的明显的特点:在UI线程将页面数据交由Render
线程渲染以后,会出现大量的空闲时间。如下图所示:

这些空闲等待时间就被浪费了。Prefetch的核心思想就是利用这部分空闲时间来预先处理item的创建和数据绑定[2]。

对比一下使用了Prefetch以后的渲染时序图如下:

时空上的复用,会大大提高页面渲染的效率,提高页面流畅度。

4. 收益

在实际开发的过程中,任何的升级都需要考量投入产出的比例。Prefetch优化影响的页面包括:

  • (1)Native页面中使用RecyclerView的页面
  • (2)weex页面中使用list的页面

    注意: 只有Android 5.0以后版本的手机才能获得这个优化。

    通过简单的升级(可能需要解决一些兼容问题),就可以使几乎所有的RecyclerView页面性能从中受益。并且在sourceCode层面不需要做额外的定制(自定义和嵌套除外)。投入产出比还是非常可观的,所以

    建议大家尽快升级吧!

5. 引用

时间: 2024-12-07 07:30:12

RecyclerView Prefetch功能探究的相关文章

Lightroom 5新功能探究

  最新版的Lightroom加入了两种新工具,同时对旧有工具做出了大幅改良.软件独特的功能与便捷的流程使其成为摄影师不可或缺的工具.修改照片模块是这篇教程关注的重点.熟悉渐变滤镜或调整画笔工具的用户一定不会对径向滤镜感到陌生,它的功能同样是帮助我们针对选定范围调整曝光.清晰度.饱和度等设置选项.和过去那些工具类似,这款工具同样能通过羽化选项设置在原图与调整范围之间创造出平滑的过渡. 和作用于整个画面的渐变滤镜不同,径向滤镜可以对任何局部进行处理.另一个有趣的新功能叫做垂直校正,它能自动分析画面

不同类型的网站首页功能探究

中介交易 SEO诊断 淘宝客 云主机 技术大厅 前段时间,看麦田博客有一篇文章在探讨mayi首页的功能问题,大意为:假设首页为一扇门,这扇门是敞开的好还是半掩着的好,敞开的门能让人一眼的看到里面有啥东西,半掩的门能给人以神秘感,增强其探索的好奇心.由于讨论的特定环境和讨论对象的背景不同,在此不对麦田的意见做评价和讨论,仅以此为出发点,谈谈对个人对网站首页功能的看法. 网站首页担负着网站"形象大使"的责任,从首页就基本能窥探出网站的定位和服务对象,个人认为,由于网站功能定位的差异化,决定

android RecyclerView:实现带header的grid

原文:RecyclerView: Grid with header  GridView和ListView有许多的相似之处,不过也有一个显著的不同:没有header和footer.现在它们两者都可以用RecyclerView实现,我想看看如何在grid上添加header. GridLayoutManager 我用GridLayoutManager创建了一个spanCount为2的RecylcerView. 注:spanCount即列数.这里GridLayoutManager的第二个参数就是span

深入解析Android中的RecyclerView组件_Android

前些日子,组里为了在目前的Android程序里实现基于ListView子项的动画效果,希望将最新的RecyclerView引入到程序中,于是我便花了一些时间研究了一下RecyclerView的基本情况.本文算是对这些日子里了解的内容做一些汇总. 在网上关于RecyclerView的基本使用方式已经有了比较详细介绍,而且其设计结构也类似于ListView,所以本文将不重点介绍如何使用,在文末的引用中都可以相关内容.这里主要是介绍RecyclerView的基本功能.设计理念,以及系统提供API的情况

深入解析Android中的RecyclerView组件

前些日子,组里为了在目前的Android程序里实现基于ListView子项的动画效果,希望将最新的RecyclerView引入到程序中,于是我便花了一些时间研究了一下RecyclerView的基本情况.本文算是对这些日子里了解的内容做一些汇总. 在网上关于RecyclerView的基本使用方式已经有了比较详细介绍,而且其设计结构也类似于ListView,所以本文将不重点介绍如何使用,在文末的引用中都可以相关内容.这里主要是介绍RecyclerView的基本功能.设计理念,以及系统提供API的情况

RecyclerView的简单使用

RecyclerView的功能很强大,本文为大家分享RecyclerView的简单使用方法. 效果图: activity_main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertica

消除11.2上的db file parallel read

客户在11.2.0.3环境中进行压力测试,发现出现大量的db file parallel read等待事件.     这个等待是11g以后才出现的,而在11g以前,一般这个等待事件发生在数据文件的恢复过程中.而11g新增了prefetch的特性,也可能导致这个等待事件的产生. 当运行压力测试时,后台的等待事件如下: SQL> select event, count(*) from v$session where username = user group by event order by 2;

iOS中登录功能的体验探究

登录功能是我在湖畔做的第一个需求. 当时PD给我的草图和下图类似: (图片来自知乎iOS客户端登录界面)  不过需求中要求用户名或者密码错误时,输入框要抖动(类似Mac登录密码错误的抖动效果). 如果实现上图的UI布局,那么输入框抖动是上下单元格独立抖动还是整体抖动? 独立抖动:会出现上下单元格边界不齐的断裂效果,破坏美感. 整体抖动:只是用户名错误,密码框为什么抖动?给用户的提示不清晰. 我个人不希望给用户不友好的信息,所以我做成了下面的效果: 由于我做的效果和PD想要的不一致,所以还产生了一

RecyclerView实现滑动删除和拖拽功能

前言 从Android 5.0开始,谷歌推出了新的控件RecyclerView,相对于早它之前的ListView,优点多多,功能强大,也给我们的开发着提供了极大的便利,今天自己学习一下RecyclerView轻松实现滑动删除及拖拽的效果,如下图. 相信研究过RecyclerView的同学,应该很清楚该怎么实现这样的效果,若是用ListView,这样的效果实现起来可能就有点麻烦,但是在强大的RecyclerView面前这样的的效果只需很少的代码,因为谷歌给我们提供了强大的工具类ItemTouchH