简介: 从“麻绳版顺滑”到“丝般顺滑”
作者:闲鱼技术-云从
1 整体思路
闲鱼在业务的快速迭代过程中,app 的长列表滑动流畅度逐步恶化,对用户浏览内容体验产生伤害。闲鱼作为国内 flutter 应用的先驱,APP 以 flutter 和原生 Native 的混合工程存在。这里分别就 Android 原生、flutter 页面和大家分享我们的优化思路。
本文分为三个部分:
- 流畅度指标和检测工具构建
- 原生 Android 长列表优化
- flutter 长列表优化
流畅度优化整体思路图如下:
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,跳帧)
- 在单位时间 1 秒内,跳过执行 Choreographer 中 doFrame() 的次数 (见 《移动App性能评测与优化》)
- SM(Smooth,流畅度)
- 在单位时间 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&