分享好友 最新动态首页 最新动态分类 切换频道
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% 的性能提升。但是离“耗时减半”还有点距离。限于篇幅原因,后续的优化详解放到下一篇继续讲解。欢迎关注我,以及时获取博客更新。

最新文章
2024年拍照手机排行榜:十款好评如潮,摄影爱好者必看
2. 小米 Civi 4 Pro:徕卡加持,时尚与性能的完美融合 小米 Civi 4 Pro吸引了众多年轻用户的目光,凭借独特的时尚设计和强大的拍照功能。它搭载了徕卡光学专业三摄,其中5000万像素徕卡光学Summilux镜头能够完美还原色彩与细节。前置仿生双
2010年全球生物技术类最具创新力公司TOP10
美国知名媒体《Fast Company》日前评出2010年度世界最具创新力公司榜,某种程度上可以视为各大公司2009年的业绩成绩单(见附录)。榜单还提供了生物技术、农业、医疗健康等多个类别的排名。下面就请随生物谷小编一起来看看2010年全球十大生
aupn油烟机24小时人工400电话/专业快速响应 - 家电 - 百科知识-蓝心网
aupn油烟机售后24小时维修服务热线:400-658-8618。aupn油烟机全市各区售后服务点热线号码。☎:400-658-8618aupn油烟机售后服务,秉承“诚信为本、客户至上”的服务态度和“以客户为中心”的服务指导思想,不仅真诚地为用户提供先进、高质
bilibili财报:B站商业推广收入51亿,日活跃用户近1亿
北京时间3月2日,哔哩哔哩(B站)公布了截至2022年12月31日的第四季度和全年未经审计的财务报告。第四季度,B站日均活跃用户达9280万,同比增长29%。用户日均使用时长达96分钟,总使用时长同比增长51%。2022年,B站总营收达219亿元人民币,
docker web版管理工具portainer
1,查询版本docker search portainer2,pull镜像,docker pull 【portainer version】3,单机版的docker,直接运行docker run -d -p 9000:9000--restart=always-v /var/run/docker.sock:/var/run/docke
2024(天河合景臻溋名铸)官方网站_官网百度百科_广州房天下
【天河合景臻溋名铸】天河合景臻溋名铸售楼处24小时电话:400-873-0112天河合景臻溋名铸开发商售楼中心预约热线:400-873-0112温馨提示:看房请务必电话提前预约,避免临时无人接待!为您安排销售全程接待并讲解,尊享优质服务!感谢您的配
AI加入影视 观众体验更优
  李 贞 宋佳航   神兽鲲鹏、异兽蠃鱼、凶兽九婴、火神祝融、水神共工等的形象,或华美壮观,或凌厉逼人,或威风凛凛,都毛发纤毫可见,而且动作流畅,特效真实……以中国古代典籍《山海经》为灵感来源的AIGC原创奇幻微短剧《山海奇镜
ComfyUI]AI换脸神器 InstantID+IPAdapter
对比lora训练,faceID,intantID,IPA,在人脸风格的迁移上,是目前AI换脸的主要方式。而最新出的InstantID,只需单个图像即可实现ID保留生成,相似度极高。InstantID,主要是使用 Contro
2024年北京电力工程监理合作加盟成立分公司的问题+2024top5电力工程监理合作加盟榜单汇总
2024年北京电力工程监理合作加盟成立分公司的问题+2024top5电力工程监理合作加盟榜单汇总
360清理大师下载安装特点
360清理大师能够有效的清理手机相关的内存,同时还有具有有效的软件管理功能,强大的加速让手机运行更流畅,一键清理快速解决空间不足问题。有兴趣的小伙伴可以360清理大师下载安装体验吧。关键用以清理系统室内空间和加快手机运作速率;能
相关文章
推荐文章
发表评论
0评