分享好友 最新动态首页 最新动态分类 切换频道
recyclerview item 滑动 recycleview快速滑动优化
2024-12-26 13:26

recyclerview item 滑动 recycleview快速滑动优化

构建 Android App 界面时,RecyclerView 出场率很高。它的加载性能影响着用户体检。本篇分享一次完整的 RecyclerView 性能优化过程:从用工具定位问题,再不断尝试各种优化方案,最终达成 50% 的性能优化。

这次性能调优的界面如下:

界面用列表的形式,展示了一个主播排行榜。

这个排行榜嵌套在一个 ViewPager 中。最初发现性能问题是因为滑动到该界面时,ViewPager 指示器的平移动画卡了一下,掉帧了。

虽然卡顿是肉眼可见的,但若不能量化卡顿,就无法量化优化程度。

第一个想到的工具是GPU 呈现模式分析。开启它的路径如下:打开手机设置 — 开发者选项 — GPU 呈现模式分析 — 在屏幕上显示为条形图:

开启后,绘制性能就会图形化展示如下:

果然有很大的性能问题,柱子都快冲出屏幕了。

虽然图形化很直观,但量化地还不够细致,绘制耗时最好能精确到毫秒。所以转战到另一种方式“在 adb shell dumpsys gfxinfo 中”。选中后,打开排行榜界面,然后输入命令adb shell dumpsys gfxinfo <包名>,最近 n 针的渲染时长就会罗列如下:

每一行代表一帧渲染中各个阶段的耗时。

用另一个命令还可以得到更加精确的数据:adb shell dumpsys gfxinfo <包名> framestats,该命令会从应用生成的最近 120 个帧中输出带有纳秒时间戳的帧时间信息:

原生输出信息没有可读性,但它们遵守 csv 格式,复制粘贴到 wps 表格中,选中 数据 — 分列,用“逗号”分割:

数据就以表格的形式展示:

每一行表示一帧绘制的时间信息,一共有 16 列,每一列表示一个关键节点的时间戳,比如PerformTraversalsStart表示绘制遍历的开始时间点,DrawStart表示onDraw()开始的时间点,前者减去后者表示measure + layout的耗时。

利用表格的求差功能可以计算出一排表征性能的耗时。

虽然得到了量化数据,但是这么折腾着实有点辛苦。

一顿搜索之后,终于找到了下面这个高效的方法:

Window.addOnFrameMetricsAvailableListener()方法可以监听最近 120 帧的绘制耗时,它的数据源和上面 adb 命令是一样的。

我把自己感兴趣的耗时都打印了出来,分别是 measure + layout、延迟、动画、触摸、绘制、总耗时。

然后打开了排行榜界面,得到了如下数据:

有一帧绘制耗时高达 435 ms,其中 measure + layout 占了 370 ms。(此数值在不同手机上差异较大)

然后我关闭了 log 过滤,发现了更多信息:

紧接着耗时最长的那一帧,有一条警告,它是由Choreographer打印的,表示此刻发生掉帧,而且掉了整整 23 帧。。。(关于 Choreographer 详细的源码解析可以点击读源码长知识 | Android卡顿真的是因为”掉帧“?)

首先想到的一个方案是:“弃用 xml”

onCreateViewHolder()执行在主线程,如果它执行耗时,势必会影响到也运行在主线程的绘制性能。

demo 中排行榜一共有两类 item:表头和表体,其中构建表头布局的代码如下:

原本这些逻辑应该写在RecyclerView.Adapter中,把它单独抽象到一个 proxy 类中,是为了解耦,以便更容易地为列表添加不同类型的表项:

调用addProxy()就动态地添加一种新表项类型(关于代理模式的实战应用可以点击代理模式应用 | 每当为 RecyclerView 新增类型时就很抓狂)。

在onCreateViewHolder()中通过解析布局文件的方式来构建表项 item。

但解析布局文件需要进行 IO 操作将布局文件读到内存中,再解析 xml 根据标签 new 出对应的控件实例,最后 addView() 到容器中。这个过程是耗时的。

如果能使用 kotlin 代码直接完成布局的构建,则可以加速这个过程。但这样的构建代码可读性很差,后期想要更改控件的某个属性很难定位。

利用 kotlin 的DSL来改善构建代码的可读性,甚至超越 xml:

关于如何使用 DSL 简化布局构建可以点击Android性能优化 | 把构建布局用时缩短 20 倍(下)

将表头和表体 item 都用DSL重构了一番,运行 demo 看看数据:

measure + layout 时间从 370 ms 缩短到 330 ms,可喜可贺~~

想到的第二个优化方案是:“替换表项的根布局”

表头和表头 item 的布局都是用了ConstraintLayout,是不是因为它太复杂了,所以导致measure + layout耗时过长?

带着怀疑,我把所有的ConstraintLayout换成了FrameLayout,界面就变成了这样:

所有子控件都聚拢在一点,再瞄一眼性能日志:

令人惊喜的是measure + layout时间从 330 ms 缩短到了 272 ms。

看来表项根布局的复杂程度的确可以影响到列表的加载性能,而且列表会放大这个性能差距,因为 n 个表项就会进行 n 次measure + layout

那就用最最简单的FrameLayout来布局吧~。通过leftMargin和topMargin来定位表项中的每一个子控件。我对着 UI 设计图,读取了每个子控件相对于父控件的左边距和上边距,然后用FrameLayout重写了表头 item。

但当我把 demo 在不同手机上运行之后,发现这个方案有缺陷,虽然已经使用了 dp 而不是像素值,但依然无法很好地解决多屏幕适配的问题:

“粉丝数”根据左边距和上边距来确定相对于父控件的位置,不同的手机屏宽度不同,所以适配效果很差。

可能这就是相对布局存在的原因,但RelativeLayout也不是省油的灯。有没有别的更简单的方法?

我想到了百分比布局,还是基于左边距和上边距,但这次不使用 dp 值,而是用相对于父控件的百分比,不就能完美解决这个问题吗?

立马搜索了一下,遗憾的发现PercentFrameLayout已经被弃用。。。

那就自己手写一个:

百分比布局的编码很简单,只需要两步:先测量所有子控件,然后按需要定位所有子控件。其中测量孩子使用ViewGroup.measureChildren()就完成了。布局孩子得先计算出父控件的宽高,然后与子控件的百分比相乘就得到了相对于父控件的位置,最后调用View.layout()来定位子控件。

运行一下 demo,效果理想~~

运用相同的思路重构了一下表体 item 。过程中发现了一个问题:并不是所有控件都可以相对于父控件来布局。

比如下面这个场景:

表项数据是服务器返回的,文字长度是可变的,“等烟雨来,就是不来”后面与它垂直对齐的图片就无法相对于父控件布局。

所以PrecentLayout不得不也引入相对布局的概念,但也不需要像ConstraintLayout那样复杂,一个简化版的百分比相对布局如下:

  • PercentLayout使用了SparseArray来存储子控件 id 和子控件引用的对应关系。其实只要拿到了View就可以拿到它的 id,为啥还要特意将这些信息存储在一个 map 结构中?因为想用空间换一点时间,否则每次都得遍历所有子控件。使用SparseArray而不是HashMap也是出于节约内存的考虑,相对而言,它有更好的内存效率,详细分析可以点击内存优化:充满矛盾的SparseArray。
  • 为PercentLayout新增了一系列相对布局属性,这些属性的语义和ConstraintLayout中的一样。但有两个比较特殊的:centerHorizontalOf表示相对于某个控件水平对齐,centerVerticalOf表示相对于某个控件垂直对齐。
  • 这一系列相对布局属性存在互斥关系,他们分为两组,一组横向,一组纵向(详见代码注释)。一个控件只能拥有一个横向属性和一个纵向属性。getChildLeft()和getChildTop分别遍历所有的横向和纵向属性,根据不同的相对位置采取不同的计算方法,以确定子控件相对于父控件的 left 和 top。

然后就可以像这样构建表体 item 的布局:

把 demo 跑起来,measure + layout 的耗时如下:

measure + layout用了 288 ms,虽然相对于FrameLayout多了十几毫秒,但是和ConstraintLayout的 330 ms 相比还是有不小的提升。

measure + layout耗时从最开始的 370 ms 经过两次优化,分别是弃用 xml和替换表项根布局,缩减到 288 ms,有了 22% 的性能提升。但是离“耗时减半”还有点距离。限于篇幅原因,后续的优化详解放到下一篇继续讲解。欢迎关注我,以及时获取博客更新。

最新文章
活动回顾 | 济南翼菲科技企业游学活动回顾
公司的产品线涵盖并联机器人、SCARA机器人、六轴机器人等,特别是在轻量级高速工业机器人领域,如迅翼系列高速并联机器人,填补了国内空白,多项性能指标优于国内外同类产品。除了专注于工业机器人的研发与制造,翼菲科技还在自动化系统集
Shopee马来西亚本土店入驻政策,Shopee马来站运费一般定多少?
Shopee作为东南亚领先的电商平台,为卖家提供了广阔的市场和多样的销售机会。对于想要入驻Shopee马来西亚本土店的卖家来说,了解入驻政策和运费设置至关重要。一、Shopee马来西亚本土店入驻政策1、入驻资格:Shopee马来西亚本土店主要面向
路由优化大师官方版 v4.5.32
  路由优化大师官方版是一款可以帮助用户更好的管理路由器的软件,为大家提供路由优化大师官方版下载、路由优化大师官方版软件介绍与路由优化大师官方版使用心得,该软件提供多种路由器的设置服务,让你更好的使用路由。  路由优化大师
网站排名在线优化工具:提高网站曝光率,轻松打造流量王者
欢迎了解SEO相关知识,图片中使用工具为:“147SEO工具”在互联网时代,网站的排名决定了品牌的曝光度,而曝光度又直接关系到网站的流量、用户的转化率和企业的盈利能力。无论是个人网站,还是企业官网,想要在激烈的竞争中脱颖而出,拥有
多地提醒:不必囤!
日本宣布于今日启动福岛核污水排海,引发全球广泛关注,部分市场出现食盐抢购现象。有消费者对日本核污水排海对广东省食盐供应安全的影响心存担忧。广东盐业集团相关负责人介绍称,目前,省、市两级食盐政府储备量和企业社会责任储备共10.8
调试了一天终于掌握结构化提示词精髓,大模型返回的数据即准确又稳定(快速收藏!)
在人工智能的探索中,结构化提示词犹如一盏明灯,指引着AI理解并回应我们的需求。 本篇文章主要大家探讨一下结构化的概念、重要性以及如何通过精心设计来优化AI对话和输出的质量。 通过这篇文章,希望能够帮助大家更有效
洪殿街道SEO常见术语合集
这些术语对普通用户来说,基本上用不到,但对于SEO人员来讲,熟悉SE0术语会有助于帮助我们更好地理解SEO。网站分类目录:网站分类目录是人为编辑的搜索结果,即将互联网上较为优秀的网站收集整理在一起,按照不同的分类或者主题放在相应的
www.0371com.cn
通过本工具可以快速查询到您站点的谷歌(www.google.com)、百度(www.baidu.com)、必应(cn.bing.com)、雅虎(cn.yahoo.com)、搜搜(www.soso.com)、搜狗(www.sogou.com)、有道(www.youdao.com)等搜索引擎收录情况及反向链接;可以快速查询到谷
营口企业网络曝光新动力,搜狗SEO助力抢占市场先机
营口搜狗SEO推广服务助力企业提升网络曝光,抢占市场份额。通过专业SEO策略,优化企业网站,提高搜索引擎排名,增强品牌影响力,助力企业实现网络营销目标。随着互联网的快速发展,企业纷纷投身于线上市场竞争,在众多搜索引擎中,搜狗凭借
已满十八岁从此进入戴好耳机的电影时代网友:让声音环绕你带来前所未有的观影享受!
当你已满十八岁,进入一个更加自由和独立的阶段,电影已经不仅仅是视觉的享受,声音的体验同样重要。已满十八岁从此进入戴好耳机的电影时代已经成为许多人观影的新习惯。耳机不仅带来了高清晰度的音效,还可以将你完全包裹在电影的世界里,
相关文章
推荐文章
发表评论
0评