
一、定位Android 的帧节拍器Choreographer 是 Android 框架层的核心类负责协调应用层的绘制节奏与屏幕的 VSync 信号确保动画、输入、绘制在正确的时间点发生。一句话Choreographer 是连接应用和屏幕刷新率的桥梁它让 App 知道什么时候该画下一帧。二、为什么需要 Choreographer屏幕刷新机制概念说明VSync屏幕硬件发出的垂直同步信号告诉系统我要刷新下一帧了刷新率60Hz 每 16.67ms 一次 VSync120Hz 每 8.33ms 一次撕裂Tearing屏幕正在刷新时缓冲区被修改导致画面上下不一致没有 Choreographer 的问题App 随意时间绘制 → 可能错过 VSync → 画面撕裂或掉帧动画帧率不稳定 → 卡顿感Choreographer 的作用接收 VSync 信号统一调度动画、输入、绘制三个任务让 App 在 VSync 到来时才开始绘制保证帧率稳定三、核心架构VSync 信号来自 SurfaceFlinger/HWC ↓ Choreographer主线程 ├── doFrame() 回调 │ ├── 处理 Input输入事件 │ ├── 处理 Animation动画 │ ├── 处理 TraversalView 绘制measure/layout/draw │ └── 提交 Buffer 到 SurfaceFlinger ↓ SurfaceFlinger 合成 → 屏幕显示四、源码核心流程1. 获取实例// 每个线程只有一个 Choreographer主线程的在 ActivityThread 中初始化ChoreographerchoreographerChoreographer.getInstance();2. 核心方法postCallback()// 三种类型的回调按优先级顺序执行publicvoidpostCallback(intcallbackType,Runnableaction,Objecttoken){// callbackType 有三种// CALLBACK_INPUT 0 输入事件最高优先级// CALLBACK_ANIMATION 1 动画// CALLBACK_TRAVERSAL 2 View 绘制measure/layout/draw}// 常用便捷方法choreographer.postFrameCallback(newFrameCallback(){OverridepublicvoiddoFrame(longframeTimeNanos){// 在下一帧 VSync 到来时执行}});3. 接收 VSyncFrameDisplayEventReceiverprivatefinalclassFrameDisplayEventReceiverextendsDisplayEventReceiverimplementsRunnable{// 1. 注册接收 VSyncpublicvoidscheduleVsync(){nativeScheduleVsync(mReceiverPtr);// 向 SurfaceFlinger 申请下一个 VSync}// 2. VSync 到来时触发native 回调OverridepublicvoidonVsync(longtimestampNanos,longphysicalDisplayId,intframe){// 发消息到主线程 HandlerMessagemsgMessage.obtain(mHandler,this);msg.setAsynchronous(true);// 异步消息优先处理mHandler.sendMessageAtTime(msg,timestampNanos/TimeUtils.NS_PER_MS);}// 3. 主线程执行Overridepublicvoidrun(){mHavePendingVsyncfalse;doFrame(mTimestampNanos,mFrame);// 执行一帧的所有回调}}4. 执行帧doFrame()voiddoFrame(longframeTimeNanos,intframe){finallongstartNanos;synchronized(mLock){// 检查是否跳帧当前时间比预期晚太多if(frameTimeNanosmLastFrameTimeNanos){scheduleVsyncLocked();// 时间不对等下一个 VSyncreturn;}// 计算预期执行时间longintendedFrameTimeNanosframeTimeNanos;startNanosSystem.nanoTime();finallongjitterNanosstartNanos-frameTimeNanos;// 如果延迟超过一帧认为跳帧了if(jitterNanosmFrameIntervalNanos){finallongskippedFramesjitterNanos/mFrameIntervalNanos;if(skippedFramesSKIPPED_FRAME_WARNING_LIMIT){Log.i(TAG,Skipped skippedFrames frames! The application may be doing too much work on its main thread.);}}mLastFrameTimeNanosframeTimeNanos;}// 按优先级执行三种回调doCallbacks(Choreographer.CALLBACK_INPUT,frameTimeNanos);doCallbacks(Choreographer.CALLBACK_ANIMATION,frameTimeNanos);doCallbacks(Choreographer.CALLBACK_TRAVERSAL,frameTimeNanos);// 执行完所有回调后再次申请下一个 VSyncscheduleFrameLocked();}五、跳帧检测原理// 核心逻辑在 doFrame() 中longjitterNanosstartNanos-frameTimeNanos;// 实际开始时间 - 预期开始时间if(jitterNanosmFrameIntervalNanos){// 延迟超过一帧间隔longskippedFramesjitterNanos/mFrameIntervalNanos;// 打印 Skipped X frames! The application may be doing too much work...}六、与 Handler 的关系组件关系Choreographer管理 VSync 接收和回调调度Handler实际的消息队列和线程切换MessageQueueChoreographer 使用setAsynchronous(true)的异步消息优先于同步屏障后的普通消息关键细节Choreographer 的 FrameHandler 使用异步消息setAsynchronous(true)配合 MessageQueue.postSyncBarrier() 机制确保 VSync 回调优先执行避免被普通 Handler 消息阻塞七、实际应用场景1. 检测 FPS / 掉帧publicclassFPSMonitorimplementsChoreographer.FrameCallback{privatelongmLastFrameTime0;privateintmFrameCount0;OverridepublicvoiddoFrame(longframeTimeNanos){if(mLastFrameTime!0){longdiffframeTimeNanos-mLastFrameTime;// 正常 16ms如果 diff 16.67ms 说明掉帧if(diff16_670_000){// 16.67ms in nanoslongdroppeddiff/16_670_000-1;Log.d(FPS,Dropped dropped frames);}}mLastFrameTimeframeTimeNanos;mFrameCount;// 继续监听下一帧Choreographer.getInstance().postFrameCallback(this);}publicvoidstart(){Choreographer.getInstance().postFrameCallback(this);}}2. 自定义动画替代 ValueAnimator// 在 VSync 回调中手动计算动画进度比 Handler.postDelayed 更精准Choreographer.getInstance().postFrameCallback(newChoreographer.FrameCallback(){longstartTime-1;OverridepublicvoiddoFrame(longframeTimeNanos){if(startTime-1)startTimeframeTimeNanos;floatprogress(frameTimeNanos-startTime)/1_000_000_000f;// 秒// 更新 UIview.setTranslationX(progress*1000);if(progress1.0f){Choreographer.getInstance().postFrameCallback(this);// 继续下一帧}}});3. 帧率同步的绘制// 游戏或自定义 View 中确保绘制与屏幕刷新同步OverridepublicvoidonDraw(Canvascanvas){// 绘制逻辑...// 请求下一帧Choreographer.getInstance().postFrameCallback(frameTime-{invalidate();// 触发重绘});}八、与相关组件的关系图VSync硬件信号16.67ms/8.33ms 间隔 ↓ SurfaceFlinger / HWC ↓ DisplayEventReceivernative接收 VSync ↓ Choreographer.FrameDisplayEventReceiver ↓ Handler主线程 Looper异步消息优先 ↓ Choreographer.doFrame() ├── CALLBACK_INPUT: InputStage输入事件分发 ├── CALLBACK_ANIMATION: ValueAnimator、ObjectAnimator 更新 └── CALLBACK_TRAVERSAL: ViewRootImpl.performTraversals() ├── measure ├── layout └── draw → SurfaceFlinger九、常见问题问题答案Choreographer 在哪个线程创建它的线程通常是主线程子线程能用吗可以但需自己创建 LooperChoreographer.getInstance()取的是当前线程的postFrameCallback 和 invalidate 区别invalidate请求重绘postFrameCallback注册 VSync 回调两者常配合使用“Skipped X frames” 怎么解决减少主线程耗时操作避免 GC优化 onDraw异步处理Choreographer 和 SurfaceFlinger 谁先发 VSyncSurfaceFlinger 接收硬件 VSync然后分发给 Choreographer十、总结Choreographer 是 Android 主线程的节拍指挥家——它监听屏幕 VSync 信号在每一帧的正确时间点按优先级依次调度输入处理、动画更新、View 绘制三大任务。如果主线程某一步慢了它就会打出 “Skipped X frames” 的警告——这是 Android 卡顿监控的第一道防线。