Choreographer

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. 优化应用功耗表现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值