跳到主要内容

Choreographer

问题

Choreographer 是什么?它如何协调 VSync 信号和 UI 渲染?

答案

Choreographer 的作用

Choreographer(编舞者)是 Android 渲染系统的核心调度器,协调 VSync 信号UI 渲染的时机:

回调类型和执行顺序

回调类型执行顺序说明
CALLBACK_INPUT1输入事件处理
CALLBACK_ANIMATION2动画计算
CALLBACK_INSETS_ANIMATION3Insets 动画
CALLBACK_TRAVERSAL4View 绘制(measure/layout/draw)
CALLBACK_COMMIT5帧提交后的清理

VSync 与帧率

VSync 信号    |----|----|----|----|----|
16ms 16ms 16ms 16ms 16ms (60fps)

理想情况:
VSync → 处理 → 提交帧 → VSync → 处理 → 提交帧

掉帧情况:
VSync → 处理耗时超过 16ms......→ VSync(错过)→ 提交帧
用户看到上一帧重复显示(Jank)

掉帧检测

// 利用 Choreographer 检测掉帧
Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback {
private var lastFrameTimeNanos = 0L

override fun doFrame(frameTimeNanos: Long) {
if (lastFrameTimeNanos != 0L) {
val durationMs = (frameTimeNanos - lastFrameTimeNanos) / 1_000_000
if (durationMs > 16) {
val droppedFrames = (durationMs / 16) - 1
Log.w("Perf", "Dropped $droppedFrames frames (${durationMs}ms)")
}
}
lastFrameTimeNanos = frameTimeNanos
// 持续监听下一帧
Choreographer.getInstance().postFrameCallback(this)
}
})

与 requestAnimationFrame 的对比

Android 的 Choreographer.postFrameCallback() 类似于浏览器的 requestAnimationFrame()

  • 都是在下一帧绘制前触发回调
  • 都以屏幕刷新率为基准
  • 都用于实现流畅动画

常见面试问题

Q1: Choreographer 和 Handler 的关系?

答案

Choreographer 底层基于 Handler 消息机制。它通过 native 层注册 VSync 信号监听(FrameDisplayEventReceiver),VSync 到来时向主线程的 Handler 发送一条异步消息(配合同步屏障,保证优先于普通消息处理)。doFrame() 在主线程中执行,按顺序触发各类型回调。

Q2: 为什么自定义动画应该使用 Choreographer.postFrameCallback 而不是 Handler.postDelayed?

答案

Handler.postDelayed(16ms) 无法精确对齐 VSync 信号,可能在两次 VSync 之间触发,导致帧不稳定。Choreographer.postFrameCallback 保证回调恰好在 VSync 信号到来后执行,与屏幕刷新完全同步,动画更流畅。实际开发中,优先使用 ValueAnimator / ObjectAnimator 等高级 API,它们内部已经使用了 Choreographer。

相关链接