Choreographer

发布于:2025-07-09 ⋅ 阅读:(16) ⋅ 点赞:(0)

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 工作流程图

应用程序 Choreographer 显示系统 postCallback() 请求VSYNC信号 VSYNC事件 执行doFrame() 处理输入 执行动画 视图遍历 loop [回调处理] 应用程序 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的工作原理,可以帮助开发者:

  1. 构建更流畅的UI体验
  2. 精准定位性能瓶颈
  3. 实现自定义动画引擎
  4. 优化应用功耗表现

网站公告

今日签到

点亮在社区的每一天
去签到