2 流畅度指标和检测工具构建
2.1 现状和难点
检测工具现状:以 Android 为例,现有流畅度工具可分为:
- 侵入式
- 集成 sdk,通过注册帧回调计算流畅度。Android 见 Choreographer 类
- profile 模式
- 无侵入式
- 执行系统命令,如
adb shell dumpsys gfxinfo ${packageName}
- 腾讯 GT APP,底层执行
service call SurfaceFlinger 1013
,高版本 Android 已不支持
流畅度指标现状有:
- FPS (Frames Per Second)
- SF(SkippedFrame,跳帧)
app 在单位时间 1 秒内,跳过执行 Choreographer 中 doFrame() 的次数 (见 《移动App性能评测与优化》)
- SM(Smooth,流畅度)
app 在单位时间 1 秒内,实际执行 Choreographer 中 doFrame() 的次数。其中 SM=60-SF。(见 《移动App性能评测与优化》)
- 帧耗时数据
使用 adb 命令得到几个关键分位的帧平均耗时:
Total frames rendered: 2245
Janky frames: 31 (1.38%)
50th percentile: 5ms
90th percentile: 10ms
95th percentile: 14ms
99th percentile: 18ms
然而以上工具和指标定义在 app 的复杂场景下,尚存在问题
- 多平台问题
现 APP 技术有原生、h5、小程序、RN、weex、flutter 等。暂无一款无侵入的流畅度检测工具能同时支持多个平台、多种机型和多个指标数据,而侵入式的检测工具无法检测竞品 APP。
- 指标选择和用户体验一致性
我们期望能有少量的几个指标数据,准确的表达用户流畅度体感。 平均 FPS(SM 和 SF 类似),不足以反映用户体验。如相同 30 FPS,可以是 1s 内 30 个 33.3 ms的画面,也可以是 29 个 16.6ms 的画面再加 1 个 516.9 ms 的画面,但用户体验并不相同。
- 流畅度数据影响因素多
滑动速度和滑动状态:idle(停止)、drag(手指拖拽)、fling(自由滑动)都是影响流畅度数据的重要因素。
2.2 流畅度指标制定
维基百科 动画定义:一种通过定时拍摄一系列多个静止的固态图像(帧)以一定频率连续变化、运动(播放)的速度(如每秒16张)而导致肉眼的视觉残象产生的错觉——而误以为图画或物体(画面)活动的作品及其影片技术。
列表滑动同理,是 APP 以一定频率(60hz下16.6ms)和不同 offset 计算出一系列静止画面,让肉眼看到滑动动画。
当我们说列表滑动不流畅,是因为频率过低无法让肉眼产生视觉残留,或在时间(画面停留时长)和空间(画面内容)产生跳变,让用户感知到变化的不自然。以此我们可以定义指标如下:
- 时间角度
- 定义平均 FPS:定义一次检测的平均帧率。反应画面平均停留时长。
- 定义 1s 大卡顿次数:平均 1s 内出现占用 3 帧及以上的画面次数。反应画面停留时长跳变
- 空间角度
- offset 跳变值:在画面不掉帧的情况,若其中一个画面出现跳变,甚至花屏或者绿屏会让用户体验到不流畅。在 APP 滑动过程中,画面内容由 offset 决定,而 offset 跳变,和卡顿时长、差值器实现均有关联,现有差值器实现基本基于 D/T 曲线(距离/时间),为此平均 FPS 和 1s 大卡顿次数很大程度上体现了画面跳变,同时考虑到无侵入式检测 offset 的难度问题,暂不考虑 offset 跳变值。
综上,我们定义流畅度指标为平均 FPS 值和 1s 大卡顿次数。
2.3 流畅度检测工具实现
我们从 APP 录屏画面入手,计算流畅度指标值。当我们得到 APP 滑动过程中的录屏数据,可通过每 16.6ms 检测录屏画面是否发生变化,当连续画面未发生变化,则表示发生了卡顿。无变化的连续画面数则表示了卡顿的时长。
为得到目标 APP 录屏数据,检测工具 APP 向系统注册录屏服务,然后在检测工具 APP 的帧回调中不停读取录屏画面,并和上次检测画面 hash 值进行比对。
- 检测工具 APP 和目标 APP 进程隔离,为此目标 APP 发生卡顿并不影响检测工具 APP 的帧回调
- 为保证每次录屏画面读取和 hash 值计算在 16.6ms 内完成,需根据高低端机型调整画面宽高压缩比。
为排除滑动操作对流畅度数值的干扰,我们使用脚本操作检测工具 APP 和目标 APP 的滑动。自动化脚本原理为使用 adb 命令操作手机
点击:adb shell input tap $x $y
滑动:adb shell input swipe $x1 $y1 $x2 $y2 $duration
2.4 检测工具演示
流畅度检测工具 APP 以悬浮框的方式显示,下面为目标检测 APP:
流畅度检测工具界面
2.5 小结和展望
在流畅度指标方面,我们定义了平均 FPS 和 1s 大卡顿次数作为指标,更好的反应了用户体验。 在流畅度检测工具方面,我们实现了无侵入检测工具,支持以下特性:
- 无侵入
- 支持检测第三方 app
- 支持多平台:native,flutter,h5,小程序
- 多维度数据:平均 FPS,平均 1s 大卡帧次数,帧分布直方图,帧分布均方差
- 自动操作,避免人为操作差异
此外,流畅度检测工具还有一些不足之处
- 列表中有视频卡片
- 停止滑动时,若列表中有视频播放,由于画面一直在变化,检测工具无法判断是滑动停止;同时,由于视频 fps 值为 30 左右,会导致流畅度数据偏低
- 如何避免:检测过程中,需保证列表滑动不停止
- 低端机(y67)真实 fps 计算存在偏差
- 为保证低端机上(如 vivo y67)上计算大图像 hash 值在 16ms 以内,录屏画面压缩较大(宽度压缩 100,高度压缩 10),为此在大量空白或者大色块的场景下,无法检测到画面的细微变化,fps 计算存在偏低。
- 如何避免:避免低端机上检测大量空白或大色块的场景
3 原生 Android 长列表优化
Android 原生长列表优化已经非常成熟了,在工具方面有 traceview、blockcanary、DDMS、Android Profile 等。常见优化手段也很多:布局层级优化,过度渲染优化,频繁measure、layout优化,UI 线程耗时方法优化、冗余资源资源加载优化等,这里不再赘述。
除此之外闲鱼使用以下 2 点优化首页
3.1 异步构建视图缓存池
通过工具检测或耗时打印,发现列表初始滑动和 loadmore 时触发 item 视图构建耗时严重(RecyclerView.onCreateViewHolder)
查看首页显示和初始滑动流程,可以发现流程中其他 UI 操作过程和等待用户操作过程均有优化空间。
利用 AsyncLayoutInflater 原理异步构建视图缓存池,优化首页列表流程如下:
其中视图缓存池构建完成的时机在不同机型下不同,可能在列表首屏多卡片构建之前,或构建中,或在用户滑动操作之前完成,或一开始构建就抛出错误停止构建
注意:不能直接使用 AsyncLayoutInflater,AsyncLayoutInflater 在异步构建失败后有一个降级到 UI 线程构建的逻辑,为避免降级逻辑发生导致缓存池在 UI 线程构建,导致页面更加卡顿,需要移除这个降级逻辑:出现异步 inflater 失败,停止缓存池构建。
3.2 ViewDataUnbinder 快速抽离 UI 操作
在卡片数据绑定阶段(RecyclerView.onBindViewHolder),在低端机上耗时较为严重,原因是在卡片数据绑定方法中,而 UI 和非 UI 操作糅合在一起,由于 UI 逻辑必须在 UI 线程执行,最终导致全部逻辑只能在 UI 线程执行。
能想到定义视图数据层,将 UI 和非 UI 操作分离开,然而实际编码发现业务代码改动量大且容易出错,AB 测试逻辑难以实现。那有没有更好的方案,用最少量代码抽离 UI 操作呢?
核心思路:编译期根据视图类自动生成 ViewData 类,并替换视图类实例。ViewData 类和视图类拥有相同的关键方法签名,方法执行时记录视图操作,统一切换到 UI 线程执行视图操作。
具体使用代码样例如下
- 注解视图类
使用 ViewDataAnno 注解视图类,UIMethodAnno 注解 UI 操作方法。
其中注解说明>
- 生成 ViewData 类
- 业务代码修改
- 修改视图变量为 ViewData 类型
- 原视图数据绑定逻辑放置后台线程
3.3 优化结果
闲鱼首页,在恢复内容上屏速度(流畅度降低)后提升流畅度
4 Flutter 复杂长列表优化
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
Android进阶资料
以下的资料是近年来,我和一些朋友面试收集整理了很多大厂的面试真题和资料,还有来自如阿里、小米、爱奇艺等一线大厂的大牛整理的架构进阶资料。希望可以帮助到大家。
Android进阶核心笔记
百万年薪必刷面试题
最全Android进阶学习视频
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
s/4304bb5a486d4c3ab8389e65ecb71ac0)
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算