当前位置: 首页 > news >正文

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() {@Overridepublic 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>() {@Overrideprotected 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 = 0Lprivate val choreographer = Choreographer.getInstance()override fun doFrame(frameTimeNanos: Long) {val currentTime = System.currentTimeMillis()if (lastFrameTime > 0) {val frameTime = currentTime - lastFrameTimeif (frameTime > 16) { // 60Hz下每帧应≈16.67msLog.w("FrameDrop", "Frame delayed: ${frameTime}ms")}}lastFrameTime = currentTimechoreographer.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() - startif (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. 优化应用功耗表现
http://www.dtcms.com/a/270251.html

相关文章:

  • 基于大模型的心肌炎全病程风险预测与诊疗方案研究
  • 使用git生成ssh的ed25519密钥
  • 鲁成伟业精彩亮相第六届中国国际无人机及无人系统博览会
  • 一个vue项目的基本构成
  • DCL学习
  • 操作系统:基本概念
  • Java结构型模式---适配器模式
  • 蓝桥杯 第十六届(2025)真题思路复盘解析
  • 【Bluedroid】BLE 地址解析列表的初始化与清除机制(btm_ble_resolving_list_init)
  • 分布式接口幂等性的演进和最佳实践,含springBoot 实现(Java版本)
  • uniapp支持单选和多选的 Vue2 版本组件
  • 从UI设计到数字孪生实战演练:构建智慧金融的智能投顾平台
  • 第十四节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - Flask 后端 生产部署讲解
  • Python之面向对象和类
  • NFT,Non-Fungible Token,非同质化代币
  • openEuler2203sp4-vg磁盘组中剔除磁盘
  • 浅谈——数据采集爬虫
  • 实战:Android 15 (API 35) 适配 构建踩坑全记录
  • 板凳-------Mysql cookbook学习 (十一--------5)
  • 《每日AI-人工智能-编程日报》--2025年7月8日
  • Softhub软件下载站实战开发(十六):仪表盘前端设计与实现
  • 香港风水(原生)林地的逻辑分类器
  • 缺乏项目进度预警机制,如何建立预警体系
  • 从零开始手写嵌入式实时操作系统
  • 【c++八股文】Day4:右值,右值引用,移动语义
  • 使用协程简化异步资源获取操作
  • qt-C++语法笔记之Stretch与Spacer的关系分析
  • Python Web应用开发之Flask框架高级应用(三)——蓝图(Blueprints)
  • openssl 生成国密证书
  • 北京-4年功能测试2年空窗-报培训班学测开-第四十五天