Android 图形渲染【2】ViewRootImpl 与 Choreographer

ViewRootImpl 和 Choreographer

关键概念:VSync 信号

  • 定义 :显示设备以固定刷新率(如 60Hz/90Hz/120Hz)刷新屏幕时,由 SurfaceFlinger 生成的垂直同步信号
  • 作用:确保渲染操作与屏幕刷新同步,避免画面撕裂(Screen Tearing),实现流畅渲染。

ViewRootImpl 概述

ViewRootImpl 是 Android 视图树的根节点,它充当了 Android 视图层次结构(View Hierarchy)与 Android 窗口系统之间的桥梁。

每个 Activity 或 Dialog 都拥有一个 Window,而每个 Window 又都对应一个 ViewRootImpl。实际上,ViewRootImpl 就是整个视图树的根,它负责以下关键任务:

  1. 视图层次结构的起点ViewRootImpl 位于应用程序 UI 视图层次结构的最顶端,它直接与 Window 相连,是 Android 系统和应用程序 UI 之间交互的起始点。用户界面上的所有显示内容都是从这个根节点开始进行绘制的。

  2. 布局、测量和绘制的协调者(Layout,Measure,Draw) :当您请求重新布局视图或需要重绘视图时,实际上是 ViewRootImpl 接收到这些请求并协调整个视图树的布局、测量和绘制过程。它会执行 performTraversals() 方法,这个方法是整个渲染管道的核心,它会依序执行:

    • performMeasure(): 测量视图树中每个视图的大小。

    • performLayout(): 根据测量的大小和布局参数,确定每个视图在屏幕上的位置。

    • performDraw(): 绘制每个视图的内容到 Surface 上,最终显示在屏幕上。

  3. 事件分发 (Event Dispatch)ViewRootImpl 也负责接收来自系统的输入事件 (例如触摸事件、按键事件等),并将这些事件分发到视图树中相应的视图进行处理。

  4. Surface 管理ViewRootImpl 负责管理与窗口相关联的 SurfaceSurface 是用于绘制图形的接口,您可以将它想象成屏幕上的一块画布。 ViewRootImpl 负责获取、配置和锁定 Surface,以便视图可以将其绘制内容渲染到 Surface 上。

Choreographer 概述

Choreographer 是 Android 图形渲染系统中至关重要的核心组件,负责协调动画、布局和绘制等操作,使其与显示设备的垂直同步信号(VSync)保持同步,进而实现流畅的用户界面渲染。

它的主要职责包括:

  1. 帧同步(Frame Synchronization)Choreographer 与屏幕的刷新率同步。大多数 Android 设备的屏幕刷新率为 60Hz (每秒刷新 60 次),这意味着系统每 16.6 毫秒 (1000ms / 60Hz) 刷新一次屏幕。 Choreographer 确保您的应用程序的绘制操作与这个刷新率同步,以避免画面撕裂 (screen tearing) 和确保流畅的动画。
  2. 安排回调(Callback Scheduling)Choreographer 会安排不同类型的回调,在每个垂直同步信号 (VSync signal) 到达时执行,这些回调类型包括:
    • 输入回调(Input Callback):处理输入事件。
    • 动画回调(Animation Callback):执行动画的更新。
    • 绘制回调(Draw Callback):执行视图的绘制操作。
    • 延迟动画回调((Deferred Animation Callback):用于在动画和绘制之间插入额外的动画步骤。
  3. VSync 信号监听Choreographer 会监听来自底层显示系统的垂直同步信号 (VSync signal)。当 VSync 信号到达时,Choreographer 就会知道新的一帧开始了,并开始执行安排好的回调。
  4. 保证流畅的 UI 渲染 : 通过与 VSync 信号同步并合理安排各类型的回调,Choreographer 帮助确保 UI 渲染的流畅性,达到 60fps 或更高的帧率,从而提供良好的用户体验。

Choreographer 是 Android 渲染系统的心跳,它协调和同步所有渲染相关的操作,确保 UI 渲染的流畅和高效。

ViewRootImpl 渲染过程

在上一篇文章中,请求绘制指令都来到了 ViewRootImpl 的 scheduleTraversals 函数中:

java 复制代码
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
      	// 发送一个同步屏障消息
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
      
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

ViewRootImpl 在 scheduleTraversals() 里先发送了一个同步屏障消息,然后调用 ChoreographerpostCallback 函数,发送了一个 mTraversalRunnable

java 复制代码
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

		final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

这里可以看出这个 TraversalRunnable 真正执行的是 ViewRootImpl 的 doTraversal()

java 复制代码
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
          	mHandler.getLooper()
              	.getQueue().removeSyncBarrier(mTraversalBarrier);
          
            performTraversals();
        }
    }
同步消息屏障的作用

scheduleTraversals() 里先发送了一个同步屏障消息,然后在 doTraversal() 中,移除了这个消息屏障,这个机制是为了确保 View 的布局、测量和绘制过程能够在一个相对 uninterrupted 的环境中进行,从而提高 UI 渲染的性能和流畅性

这里发送同步屏障的是 mHandler,它的类型是 ViewRootHandler,它用来处理一些 UI 相关的消息,比如执行 invalidate,屏幕移除,处理输入事件等。

scheduleTraversals() 中,给编舞者发了一个 CALLBACK_TRAVERSAL 类型的 Callback:

java 复制代码
mChoreographer.postCallback(
        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

也就是说同步屏障在这里保证的就是这个 Callback 对应的异步消息能够尽快处理。

同步屏障在 performTraversals() 执行之前被移除。 这似乎有些反直觉,但实际上,同步屏障的主要目的是 CALLBACK_TRAVERSAL 消息被处理之前生效,并在 Traversal 过程开始之前被移除

同步屏障的重点在于创建一个更干净的消息处理环境,以便 performTraversals 能够 更快速地开始执行,而不是让 performTraversals 本身在屏障期间被优先执行

真正的处理渲染过程

doTraversal() 中,移除了消息屏障,然后执行 performTraversals()performTraversals() 是 ViewRootImpl 的核心方法,performTraversals() 主要处理三个核心步骤:measure(测量)、layout(布局)、draw(绘制):

1. 测量(Measure)

关键代码

java 复制代码
// 测量视图层级
windowSizeMayChange |= measureHierarchy(host, lp, resources, desiredWidth, desiredHeight, optimize);

// 执行具体测量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

核心逻辑

  • 通过 measureHierarchy 递归测量所有子视图的尺寸。
  • 根据窗口参数(如 WRAP_CONTENT)动态调整测量规格。
  • 权重(Weight)处理:若布局参数包含权重,可能触发多次测量。
2. 布局(Layout)

关键代码

java 复制代码
// 执行布局
performLayout(lp, mWidth, mHeight);

// 处理透明区域
if ((host.mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
    host.gatherTransparentRegion(mTransparentRegion);
    mTransaction.setTransparentRegionHint(sc, mTransparentRegion);
}

核心逻辑

  • 调用 performLayout 确定所有子视图的位置。
  • 收集透明区域信息,通过 SurfaceControl.Transaction 告知系统优化合成。
3. 绘制(Draw)

关键代码

java 复制代码
// 触发绘制
if (!cancelAndRedraw) {
    performDraw();
} 

// 硬件加速初始化
if (surfaceCreated && mAttachInfo.mThreadedRenderer != null) {
    mAttachInfo.mThreadedRenderer.initialize(mSurface);
    mAttachInfo.mThreadedRenderer.allocateBuffers();
}

核心逻辑

  • 调用 performDraw 生成绘制命令,通过 CanvasThreadedRenderer 渲染内容。
  • 若启用硬件加速,初始化渲染器并将 Surface 绑定到 GPU。
4. Surface 管理

关键代码

java 复制代码
// 与 WindowManagerService 通信更新 Surface
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

// Surface 状态处理
if (surfaceCreated) {
    mFullRedrawNeeded = true; // Surface 新建需完全重绘
} else if (surfaceDestroyed) {
    destroyHardwareResources(); // Surface 销毁释放资源
}

核心逻辑

  • 通过 relayoutWindow 更新窗口布局并获取新的 Surface。
  • 根据 Surface 状态(新建/销毁/替换)触发渲染器初始化或资源释放。
5. 合成与提交

关键代码

java 复制代码
// 提交绘制结果
if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
    mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
} else {
    drawSoftware(surface, mAttachInfo, xOffset, yOffset);
}

核心逻辑

  • 通过 ThreadedRenderer.draw(硬件加速)或 drawSoftware(软件绘制)提交帧数据。
  • 最终通过 SurfaceFlinger 合成到屏幕。
核心流程总结
  1. 测量:递归计算所有视图的尺寸。
  2. 布局:确定所有视图的位置。
  3. Surface 准备:通过 WMS 获取/更新 Surface。
  4. 绘制:生成像素数据并提交到 Surface。
  5. 合成:由系统将 Surface 内容显示到屏幕。

Choreographer 协调渲染过程

postCallback

ViewRootImpl 中通过 mChoreographer 的 postCallback 函数发送了一个 TraversalRunnable 来执行绘制流程,下面进入 Choreographer 的部分,首先从 postCallback 开始:

java 复制代码
mChoreographer.postCallback(
        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

postCallback 内部本质是调用 postCallbackDelayedInternal

java 复制代码
    private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

首先加锁确保同步,然后根据开机时间计算出合理的执行时间,即当前系统启动以来的毫秒数 ,然后将这个 callback 添加到 mCallbackQueues,这是一个回调队列数组Choreographer 使用它来管理不同类型的回调。数组的索引就是 callbackType,每个元素 mCallbackQueues[callbackType] 都是一个 CallbackQueue 对象,负责管理特定类型的所有待执行回调。

addCallbackLocked(dueTime, action, token); 方法负责将新的回调任务添加到指定类型 (callbackType) 的回调队列 中,队列中按照 dueTime 排序 (通常是按到期时间升序排列)。

if (dueTime <= now) : 判断回调的到期时间是否已经到达或已经过期 。如果 delayMillis 为 0 或负数,或者由于系统时钟偏差等原因导致 dueTime 小于等于 now,则表示回调应该立即执行 (或者尽快在下一个 VSync 信号到达时执行)。

scheduleFrameLocked(now); : 立即调度一个帧 (Frame)scheduleFrameLocked 方法 (也是 Choreographer 类的方法,并且线程安全) 的作用是请求在下一个 VSync 信号到达时执行帧处理。这会触发 Choreographer 的核心渲染流程,在 VSync 信号到达时,会检查并执行所有到期的回调队列中的回调任务 (包括刚刚添加的这个)。

否则,发送 Handler 异步消息,在未来延迟执行。

scheduleFrameLocked 请求下一帧渲染

进入 scheduleFrameLocked , 看看编舞者是如何调度一个帧的:

java 复制代码
    private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            if (USE_VSYNC) {
            
                // 如果正在 Looper 线程上运行,那么立即安排垂直同步(vsync);
                // 否则,发布一条消息以便尽快从用户界面(UI)线程安排垂直同步。
                if (Looper.myLooper() == mLooper) {
                    scheduleVsyncLocked();
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtFrontOfQueue(msg);
                }
            } else {
                final long nextFrameTime = Math.max(mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextFrameTime);
            }
        }
    }

scheduleFrameLocked 中,如果不是立即执行的消息,通过 FrameHandler (mHandler)发送了一个

MSG_DO_FRAME 的异步消息到主线程。

而立即执行的消息,帧调度核心逻辑在 scheduleVsyncLocked 方法:

java 复制代码
private void scheduleVsyncLocked() {
    mDisplayEventReceiver.scheduleVsync();
}

mDisplayEventReceiver 的类型是 FrameDisplayEventReceiver ,它是 Choreographer 里面的一个核心组件 ,它的主要职责是接收来自系统底层的 VSync 信号 ,并将这些信号传递给 Choreographer 进行处理,从而驱动整个渲染流程。 你可以把它想象成是 ChoreographerVSync 信号接收器和处理者

DisplayEventReceiver
java 复制代码
    private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
        private boolean mHavePendingVsync;
        private long mTimestampNanos;
        private int mFrame;
        private final VsyncEventData mLastVsyncEventData = new VsyncEventData();

        FrameDisplayEventReceiver(Looper looper, int vsyncSource, long layerHandle) {
            super(looper, vsyncSource, 0, layerHandle);
        }

        @Override
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
                VsyncEventData vsyncEventData) {
            try {
                long now = System.nanoTime();
                if (timestampNanos > now) {
                    timestampNanos = now;
                }

                if (!mHavePendingVsync) {
                    mHavePendingVsync = true;
                }

                mTimestampNanos = timestampNanos;
                mFrame = frame;
                mLastVsyncEventData.copyFrom(vsyncEventData);
                Message msg = Message.obtain(mHandler, this);
                msg.setAsynchronous(true);
              	// 这里的 mHandler 是 FrameHandler 类型
                mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
            }
        }

        @Override
        public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
        }
    }

这里把 VSync 事件作为一个消息 (Message) 投递到 Handler 去处理,而不是直接在 onVsync() 回调方法里立即处理。目的是通过 Handler 消息机制来平衡 VSync 事件处理的及时性和消息队列的公平性。

  • 不直接在 onVsync() 中处理: 避免 VSync 事件处理"饿死"消息队列,保证 Handler 线程能够公平地处理各种类型的任务,维持应用的整体响应性。
  • 将 VSync 事件投递到 Handler 消息队列: 将 VSync 事件的处理纳入到 Handler 的消息调度体系中,与其他类型的消息统一管理。
  • 仍然可以 "立即" 处理 (相对于队列顺序): 在消息队列空闲或者没有更早消息的情况下,VSync 事件消息仍然可以很快得到处理,保证了帧绘制的及时性。
  • 保证更早消息的优先处理: 如果消息队列中有更早的消息,则优先处理更早的消息,体现了消息队列的 FIFO 原则,保证了消息处理的顺序性和公平性。

总而言之,这种设计是一种折衷和权衡 ,在 帧绘制的及时性消息队列的公平性 之间找到一个平衡点,既要保证 UI 渲染能够及时响应 VSync 信号,又要避免 VSync 事件处理 "霸占" 线程资源,影响其他重要任务的执行,最终目的是为了提升 Android 系统的整体性能和用户体验。

Choreographer 收到了 VSync 信号后,通过 FrameHandler 发送了一个消息。

而上面的 DisplayEventReceiver 的 scheduleVsync 方法:

java 复制代码
    public void scheduleVsync() {
        if (mReceiverPtr == 0) {
            // log something
        } else {
            nativeScheduleVsync(mReceiverPtr);
        }
    }

从这里进入 native 层,也就是说 Vsync 信号来自于底层。

FrameHandler

可以看出,每一帧的时机到来,都通过 Handler 机制,将消息发送到主线程,在主线程执行帧绘制操作。

FrameHandlerChoreographer 类中的一个私有内部类 ,它继承自 HandlerFrameHandler 在这里专门用来处理 Choreographer 内部的消息,驱动着 Choreographer 的核心运作。

java 复制代码
    private final class FrameHandler extends Handler {
        public FrameHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_DO_FRAME:
                    doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
                    break;
                case MSG_DO_SCHEDULE_VSYNC:
                    doScheduleVsync();
                    break;
                case MSG_DO_SCHEDULE_CALLBACK:
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
    }
doFrame

触发一帧的绘制操作doFrame() 方法是 Choreographer 最核心的方法之一,它负责执行实际的帧绘制工作,包括执行所有类型的回调(输入、动画、绘制、延迟动画),完成一帧画面的渲染。

java 复制代码
void doFrame(long frameTimeNanos, int frame, DisplayEventReceiver.VsyncEventData vsyncEventData) {
    synchronized (mLock) { // 线程同步锁
        if (!mFrameScheduled) { // 检查是否需要调度帧
            return;
        }
        // ... (省略:时间抖动校正、跳帧检测、帧时间倒退/FPS限制检查 等细节) ...
        // ... (省略:记录 VSync 信息、更新状态 等细节) ...
    } // 结束 synchronized 区块

    // 锁定动画时钟 (同步动画时间)
    AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
    // 执行各阶段的回调 (核心渲染阶段)
    doCallbacks(Choreographer.CALLBACK_INPUT, frameIntervalNanos);      // 输入回调
    doCallbacks(Choreographer.CALLBACK_ANIMATION, frameIntervalNanos);    // 动画回调
    doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameIntervalNanos);// Insets 动画回调
    doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos);   // Traversal 回调 (布局/测量)
    doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos);      // Commit 回调 (提交)

    // 解锁动画时钟
    AnimationUtils.unlockAnimationClock();
}

核心渲染阶段在 doCallbacks:

java 复制代码
void doCallbacks(int callbackType, long frameIntervalNanos) {
    CallbackRecord callbacks;
    long frameTimeNanos = mFrameData.mFrameTimeNanos;
    synchronized (mLock) {
        // 获取到期的回调列表
        final long now = System.nanoTime();
        callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                now / TimeUtils.NANOS_PER_MS);
        if (callbacks == null) {
            return; // 如果没有到期的回调,直接返回
        }
        mCallbacksRunning = true; // 标记回调开始运行

        // ... (省略: Commit 回调的 Jitter 补偿和帧时间调整 的细节) ...
    }

    try {
        // 遍历并执行回调函数
        for (CallbackRecord c = callbacks; c != null; c = c.next) {
            c.run(mFrameData); // 执行回调函数的核心方法
        }
    } finally {
        synchronized (mLock) {
            mCallbacksRunning = false; // 标记回调运行结束
            // 回收 CallbackRecord 对象 (为了复用)
            do {
                final CallbackRecord next = callbacks.next;
                recycleCallbackLocked(callbacks);
                callbacks = next;
            } while (callbacks != null);
        }
    }
}

这里就是从 mCallbackQueues 取出不同类型消息的回调并执行,在 postCallback 中,有向 mCallbackQueues 添加回调的逻辑,也就是会执行到 ViewRootImpl 的 doFrame 函数中执行 View 的真正绘制流程。

doScheduleVsync

请求调度 VSync 信号, 向系统底层请求 VSync 信号,以便在下一个 VSync 信号到来时开始新的帧绘制。

java 复制代码
    void doScheduleVsync() {
        synchronized (mLock) {
            if (mFrameScheduled) {
                scheduleVsyncLocked();
            }
        }
    }

最终会调用到 mDisplayEventReceiver 的 scheduleVsync 函数:

java 复制代码
    public void scheduleVsync() {
        if (mReceiverPtr == 0) {
            // log something
        } else {
            nativeScheduleVsync(mReceiverPtr);
        }
    }

调用 native 方法请求 VSync。

doScheduleCallback

检查并调度帧,以便及时执行特定类型的延期回调 (Delayed Callback) ,根据 callbackType 参数,从对应的回调队列中取出所有到期的回调函数,并执行它们。

java 复制代码
    void doScheduleCallback(int callbackType) {
        synchronized (mLock) {
            if (!mFrameScheduled) {
                final long now = SystemClock.uptimeMillis();
              	// 检查是否存在需要立即执行的 callback
                if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                    scheduleFrameLocked(now);
                }
            }
        }
    }

直接去从 mCallbackQueues 找是否存在到期的 Delay Callback 需要执行,从而能够尽快安排下一帧的渲染流程,从而触发这些回调的执行。

小结
  • 消息接收和分发中心: FrameHandlerChoreographer 内部的消息处理中心,它接收来自 Choreographer 线程消息队列的消息,并根据消息类型进行分发处理。
  • 驱动帧渲染流程: 通过处理 MSG_DO_FRAME 消息,FrameHandler 触发 doFrame() 方法,启动一帧的完整渲染流程,包括执行各种回调和绘制操作。
  • 调度 VSync 信号: 通过处理 MSG_DO_SCHEDULE_VSYNC 消息,FrameHandler 触发 doScheduleVsync() 方法,请求系统调度 VSync 信号,实现与屏幕刷新的同步。
  • 执行延迟回调: 通过处理 MSG_DO_SCHEDULE_CALLBACK 消息,FrameHandler 触发 doScheduleCallback() 方法,执行各种类型的延迟回调,包括输入事件处理、动画更新和绘制等。

总结

scss 复制代码
应用程序 UI 代码 (View.invalidate())
    ↓
View.invalidate()  -> mParent.invalidateChild(...)  (请求向上冒泡)
    ↓
... (invalidate 请求在 View 树中向上冒泡) ...
    ↓
DecorView.invalidate() -> ViewRootImpl.invalidateChildInParent(...)
    ↓
ViewRootImpl.invalidateChildInParent()  ->  ViewRootImpl.scheduleTraversals()  (请求 Traversal 调度)
    ↓
ViewRootImpl.scheduleTraversals() -> Choreographer.postCallback(CALLBACK_TRAVERSAL, action, null)
    ↓
Choreographer.postCallback()  检查 CALLBACK_TRAVERSAL 队列是否为空,如果为空,则调用 Choreographer.scheduleFrameLocked()
    ↓
Choreographer.scheduleFrameLocked() -> mDisplayEventReceiver.scheduleVsync()  (请求 VSync 信号)
    ↓
SurfaceFlinger 生成 VSync 信号,通过 DisplayEventReceiver 的 onVSync 回调给 Choreographer
    ↓
DisplayEventReceiver  ->  Choreographer.FrameHandler  (发送 MSG_DO_FRAME 消息)
    ↓
Choreographer.FrameHandler  ->  Choreographer.doFrame(frameTimeNanos, vsyncSeq)  (启动帧渲染流程)
    ↓
Choreographer.doFrame()  -> 执行 CALLBACK_TRAVERSAL 队列中的任务 (mTraversalRunnable -> ViewRootImpl.performTraversals())
    ↓
ViewRootImpl.performTraversals()  ->  View 树 Measure, Layout, Draw
    ↓
最终渲染结果显示在屏幕上

Choreographer 基于 VSync 信号,通过 doFrame() 方法驱动渲染流程。 Choreographer 是渲染流程的 调度器指挥家

SurfaceFlinger 发送的 VSync 信号是最底层的触发器 , 它驱动了 ChoreographerdoFrame() 方法,进而驱动了整个 Android 图形渲染管道。

在请求渲染之后,通过 Choreographer 接管渲染调度,来安排渲染的执行,最终交给 ViewRootImpl 去执行渲染绘制。

相关推荐
IT猿手14 分钟前
2025最新高维多目标优化:基于城市场景下无人机三维路径规划的导航变量的多目标粒子群优化算法(NMOPSO),MATLAB代码
android·开发语言·算法·机器学习·matlab·无人机
AlexMercer10121 小时前
Java 入门第一课 InteliJ IDEA 的快捷操作
android·java·开发语言·ide·笔记·intellij-idea
五味香2 小时前
C语言学习,希尔排序
android·c语言·开发语言·数据结构·学习·算法·排序算法
pengyu3 小时前
系统化掌握Flutter开发之Stack:布局系统中的"瑞士军刀”
android·flutter·dart
飞猿_SIR6 小时前
最新版本Exoplayer(MediaX)实现K歌原伴唱包括单音轨和双音轨
android·ffmpeg·音视频
练小杰8 小时前
【Mysql】我在广州学Mysql 系列——Mysql 性能优化
android·数据库·经验分享·sql·mysql·性能优化·性能
她似晚风般温柔78910 小时前
鸿蒙开发深入浅出04(首页数据渲染、搜索、Stack样式堆叠、Grid布局、shadow阴影)
android·鸿蒙·纯血鸿蒙
ShawnRacine11 小时前
Flutter-Android编译报错与解决方案汇总
android·flutter
Python私教11 小时前
Flutter 实现抖音风格底部导航栏
android·开发语言·javascript