This page looks best with JavaScript enabled

使用 OnFrameMetricsAvailableListener 统计绘制耗时

 ·  ☕ 2 min read
    🏷️

在 Android 7.0, 增加了一个 Api 可以方便的统计一个 Window 的 View 树的绘制耗时。

功能

统计渲染子系统报告的帧生命周期中各个里程碑的时序数据。可以通过其相应的标识符查询支持的指标。

各个里程碑就是指:

FrameMetrics 指标 说明
ANIMATION_DURATION 表示执行动画回调的耗时
COMMAND_ISSUE_DURATION 表示向 GPU 发出绘制命令的耗时
DRAW_DURATION 表示将 View 树转换为 DisplayList 的耗时
FIRST_DRAW_FRAME 表示当前帧是否是当前 Window 布局中绘制的第一帧
INPUT_HANDLING_DURATION 表示处理输入事件回调的耗时
INTENDED_VSYNC_TIMESTAMP 当前帧的预期开始时间, 如果此值与 VSYNC_TIMESTAMP 不同,则表示 UI 线程上发生了阻塞,阻止了 UI 线程及时响应vsync信号
LAYOUT_MEASURE_DURATION 表示对 View 树进行 measure 和 layout 所花的时间
SWAP_BUFFERS_DURATION 表示将此帧的帧缓冲区发送给显示子系统所花的时间
SYNC_DURATION 表示将 DisplayList 与渲染线程同步所花的时间
TOTAL_DURATION 表示此帧渲染并发布给显示子系统所花费的总时间, 等于所有其他具有时间价值的指标的值之和
UNKNOWN_DELAY_DURATION 表示等待 UI 线程响应并处理帧所经过的时间, 大多数情况下应为0
VSYNC_TIMESTAMP 在所有 vsync 监听器和帧绘制中使用的时间值(Choreographer 的帧回调, 动画, View#getDrawingTime等)

时间单位都是纳秒

以上所有指标都存储在一个 long 类型的数组中, 使用 FrameMetrics#getMetric 方法可以从中提取。

使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
val thread = HandlerThread("frame-stat").apply { start() }
val handler = Handler(thread.looper)
window.addOnFrameMetricsAvailableListener(Window.OnFrameMetricsAvailableListener { _, metric,_ ->
    // 会在 handler 对应的 thread 中执行
    val copy = FrameMetrics(metric) /* 注意需要做深拷贝, 再使用 */
    val vsycn = copy.getMetric(FrameMetrics.VSYNC_TIMESTAMP)
    val intended = copy.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP)
    Log.d("FrameStat", "is first frame: ${copy.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1L} ")
    Log.d("FrameStat", "measure layout: ${copy.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION) / 1000000} ms")
    Log.d("FrameStat", "draw: ${copy.getMetric(FrameMetrics.DRAW_DURATION) / 1000000} ms")
    Log.d("FrameStat", "total: ${copy.getMetric(FrameMetrics.TOTAL_DURATION) / 1000000} ms")
    Log.d("FrameStat", "delay draw: ${copy.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP) > copy.getMetric(FrameMetrics.VSYNC_TIMESTAMP)} ms")
    Log.d("FrameStat", "=============")
}, handler)
D: is first frame: false 
D: measure layout: 0 ms
D: draw: 4 ms
D: total: 52 ms
D: delay draw: false ms
D: =============
D: is first frame: false 
D: measure layout: 1 ms
D: draw: 0 ms
D: total: 18 ms
D: delay draw: false ms
D: =============

参考


Yang
WRITTEN BY
Yang
Developer