Choreographer 深度解析
一、Choreographer 核心概念
Choreographer 是 Android 系统中协调动画、输入和绘制时序的关键组件,它通过 VSYNC 信号来同步 UI 操作。
1. 核心职责
- 帧同步:协调应用与显示刷新率(通常60Hz)
- 回调调度:管理以下回调类型的执行时序:
CALLBACK_INPUT
(输入事件)CALLBACK_ANIMATION
(动画)CALLBACK_INSETS_ANIMATION
(插入动画)CALLBACK_TRAVERSAL
(视图遍历/绘制)CALLBACK_COMMIT
(帧提交)
2. VSYNC 机制
// 简化的VSYNC请求流程
Choreographer.getInstance().postFrameCallback(new FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
// 在下一个VSYNC信号时执行
}
});
二、关键源码解析(基于Android 13)
1. 初始化流程
// 单例获取
public static Choreographer getInstance() {
return getInstance(Looper.myLooper());
}
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
return new Choreographer(looper, VSYNC_SOURCE_APP);
}
};
2. 回调队列管理
// 回调类型定义
private static final int CALLBACK_INPUT = 0;
private static final int CALLBACK_ANIMATION = 1;
// ...其他类型
// 使用CallbackQueue数组管理不同优先级队列
private final CallbackQueue[] mCallbackQueues;
3. 帧回调处理
void doFrame(long frameTimeNanos, int frame) {
// 1. 计算掉帧情况
final long jitterNanos = frameTimeNanos - mLastFrameTimeNanos;
if (jitterNanos >= mFrameIntervalNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! ");
}
}
// 2. 按顺序执行各阶段回调
doCallbacks(CALLBACK_INPUT, frameTimeNanos);
doCallbacks(CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(CALLBACK_INSETS_ANIMATION, frameTimeNanos);
doCallbacks(CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(CALLBACK_COMMIT, frameTimeNanos);
}
三、高级应用技巧
1. 精确帧率监控
class FrameMonitor : Choreographer.FrameCallback {
private var lastFrameTime = 0L
private val choreographer = Choreographer.getInstance()
override fun doFrame(frameTimeNanos: Long) {
val currentTime = System.currentTimeMillis()
if (lastFrameTime > 0) {
val frameTime = currentTime - lastFrameTime
if (frameTime > 16) { // 60Hz下每帧应≈16.67ms
Log.w("FrameDrop", "Frame delayed: ${frameTime}ms")
}
}
lastFrameTime = currentTime
choreographer.postFrameCallback(this)
}
}
2. 自定义动画调度
// 创建高优先级动画调度器
public void scheduleAnimation(Animator animator) {
Choreographer.getInstance().postCallback(
Choreographer.CALLBACK_ANIMATION,
() -> animator.doAnimationFrame(
Choreographer.getInstance().getFrameTime()),
null);
}
3. 性能优化实践
优化点1:减少Traversal回调负担
// 避免在绘制阶段做耗时操作
view.doOnPreDraw {
// 轻量级操作
post {
// 耗时操作延后执行
heavyOperation()
}
}
优化点2:批量更新动画
// 合并多个属性动画到单个回调
ValueAnimator.setFrameDelay(0); // 使用系统默认帧率
Choreographer.getInstance().postFrameCallback(frameTime -> {
animatorSet1.doTrame(frameTime);
animatorSet2.doTrame(frameTime);
});
四、Choreographer 工作流程图
五、常见问题解决方案
1. 主线程卡顿检测
fun setupFrameMonitor() {
val handler = Handler(Looper.getMainLooper())
val monitor = object : Runnable {
override fun run() {
val start = SystemClock.uptimeMillis()
Choreographer.getInstance().postFrameCallback {
val cost = SystemClock.uptimeMillis() - start
if (cost > 50) { // 阈值可根据需求调整
reportJank(cost)
}
}
handler.postDelayed(this, 1000) // 每秒检测一次
}
}
handler.post(monitor)
}
2. 动画掉帧优化
// 使用SurfaceView替代普通View进行复杂动画
surfaceHolder.lockCanvas().apply {
// 在此直接绘制
surfaceHolder.unlockCanvasAndPost(this)
}
// 通过Choreographer控制帧率
fun startCustomAnimation() {
val choreographer = Choreographer.getInstance()
val callback = object : Choreographer.FrameCallback {
override fun doFrame(frameTimeNanos: Long) {
updateAnimation(frameTimeNanos)
choreographer.postFrameCallback(this) // 维持动画循环
}
}
choreographer.postFrameCallback(callback)
}
六、平台差异说明
特性 | Android 4.1 (Jelly Bean) | Android 5.0 (Lollipop) | Android 12+ |
---|---|---|---|
VSYNC 同步 | 引入Project Butter | 支持三重缓冲 | 动态刷新率支持 |
回调类型 | 基础3种类型 | 增加INSETS类型 | 新增COMMIT阶段 |
帧延迟检测 | 简单日志警告 | 完善的Jank统计 | 集成到Perfetto |
掌握Choreographer的工作原理,可以帮助开发者:
- 构建更流畅的UI体验
- 精准定位性能瓶颈
- 实现自定义动画引擎
- 优化应用功耗表现