View绘制流程—performResumeActivity—>performTraversals

本文从ActivityThread的handleResumeActivity()方法开始,追踪View的绘制流程,经过WindowManagerImpl的addView(),ViewRoot的setView()、requestLayout()和scheduleTraversals(),最终在ViewRoot的handleMessage()中触发performTraversals(),揭示Android视图绘制的起点和关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言


我们知道AMS启动一个APP(Launcher——>AMS—>MyAPP)会创建ActivityThread。也就是ActivityThread是一个App的真正入口,分析View的绘制流程,我们肯定是以ActivityThread为起点来分析。然后抵达一个方法performTraversals。这个方法是ViewRoot内的一个方法,也是View绘制的真实起点。我们先不讨论它们的具体,本文主要目的是看在它被执行之前都经历了哪些流程。

参考1.Launcher启动流程及初始化
参考2.ActivityThread分析—ActivityThread的main方法是如何被调用的
参考3.ActivityThread分析—ActivityThread的main方法的执行流程分析

代码分析


frameworks\base\core\java\android\app\ActivityThread.java#handleResumeActivity()

wm是WindowManger,其实现类为WindowMangerImpl,我们去看它的addView方法。


    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
   
   
               ......
        if (r != null) {
   
   
               ......
            if (r.window == null && !a.mFinished && willBeVisible) {
   
   
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.</
<think>我们正在讨论Android视图绘制流程中从scheduleTraversals到performTraversals的详细过程。根据之前的引用和讨论,我们知道ViewRootImpl是连接WindowManager和DecorView的纽带,负责整个视图树的测量、布局和绘制。而scheduleTraversals是触发整个视图树遍历(即measure, layout, draw)的关键方法。 现在,我们重点分析从scheduleTraversals到doTraversal再到performTraversals的流程: 1. **scheduleTraversals()**: - 当需要更新视图时(例如调用了requestLayout()),最终会调用到ViewRootImpl的scheduleTraversals()方法。 - 该方法的作用是安排一次遍历(traversal),但不会立即执行,而是通过Choreographer在下一个VSYNC信号到来时执行。 - 为了避免同一帧内多次安排遍历,它使用了一个同步屏障(mTraversalBarrier)和一个标志位mTraversalScheduled来确保只安排一次。 2. **Choreographer与VSYNC**: - scheduleTraversals()内部会通过Choreographer.postCallback()方法注册一个回调,这个回调将在下一个VSYNC信号到来时执行。 - 这个回调实际上就是执行mTraversalRunnable(它内部调用了doTraversal())。 3. **doTraversal()**: - 当VSYNC信号到来时,Choreographer会回调mTraversalRunnable,进而调用doTraversal()。 - doTraversal()首先会移除同步屏障(mTraversalBarrier),然后调用performTraversals()。 4. **performTraversals()**: - 这是整个视图树绘制的核心方法,它依次执行measure(测量)、layout(布局)和draw(绘制)三个步骤。 - 在measure阶段,它会根据窗口的尺寸和自身的LayoutParams计算出根视图的MeasureSpec,然后开始整个视图树的测量。 - 在layout阶段,它会确定每个视图的位置。 - 在draw阶段,它会将视图绘制到Surface上。 下面我们用序列图来表示这个流程: ```mermaid sequenceDiagram participant ViewRootImpl participant Choreographer participant VSYNC ViewRootImpl->>ViewRootImpl: scheduleTraversals() ViewRootImpl->>Choreographer: postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null) Choreographer->>VSYNC: 等待下一个VSYNC信号 VSYNC->>Choreographer: 信号到达 Choreographer->>ViewRootImpl: 执行mTraversalRunnable ViewRootImpl->>ViewRootImpl: doTraversal() ViewRootImpl->>ViewRootImpl: 移除同步屏障 ViewRootImpl->>ViewRootImpl: performTraversals() ViewRootImpl->>ViewRootImpl: performMeasure() ViewRootImpl->>ViewRootImpl: performLayout() ViewRootImpl->>ViewRootImpl: performDraw() ``` 详细步骤说明: 1. **scheduleTraversals()**: ```java void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; // 设置同步屏障,确保异步消息优先执行 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); // 向Choreographer注册一个回调 mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); // ... 其他处理 } } ``` 2. **mTraversalRunnable**: ```java final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } ``` 3. **doTraversal()**: ```java void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; // 移除同步屏障 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); // 执行真正的遍历 performTraversals(); } } ``` 4. **performTraversals()**: - 这个方法非常长,它根据各种状态(如窗口尺寸变化、布局参数变化等)来决定是否需要重新测量、布局和绘制。 - 它会依次调用`performMeasure()`, `performLayout()`, `performDraw()`三个方法。 关键点: - **同步屏障**:在scheduleTraversals中设置同步屏障,确保在VSYNC信号到来时,优先执行遍历操作(因为遍历操作是异步消息)。 - **VSYNC同步**:通过Choreographer将遍历操作与VSYNC信号同步,避免掉帧和界面撕裂。 - **避免重复调度**:通过mTraversalScheduled标志位确保同一帧内不会多次调度遍历。 通过以上流程,Android系统保证了视图的更新能够高效、有序地进行,并与屏幕刷新率保持一致,从而提供流畅的用户体验。 §§相关问题§§ 1. 同步屏障(Sync Barrier)在Android消息机制中是如何工作的? 2. Choreographer在Android绘制流程中扮演什么角色? 3. 为什么在doTraversal()中需要移除同步屏障?</think>### Android视图绘制流程:从`scheduleTraversals`到`performTraversals`详解 #### 一、核心流程概览 ```mermaid sequenceDiagram ViewRootImpl->>Choreographer: scheduleTraversals() Choreographer->>VSYNC: 注册回调 VSYNC-->>Choreographer: 信号到达 Choreographer->>ViewRootImpl: 执行mTraversalRunnable ViewRootImpl->>ViewRootImpl: doTraversal() ViewRootImpl->>ViewRootImpl: performTraversals() ViewRootImpl->>ViewRootImpl: performMeasure() ViewRootImpl->>ViewRootImpl: performLayout() ViewRootImpl->>ViewRootImpl: performDraw() ``` #### 二、关键步骤解析 1. **scheduleTraversals()** - 触发时机:当视图需要更新时(如`requestLayout()`或`invalidate()`) - 核心作用:安排下一次遍历(traversal),但不立即执行 - 源码关键逻辑: ```java // ViewRootImpl.java void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; // 设置同步屏障,确保UI操作优先执行 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); // 通过Choreographer注册VSYNC回调 mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); } } ``` [^3] 2. **VSYNC同步机制** - 通过`Choreographer`注册回调,等待下一个垂直同步信号(VSYNC) - 确保绘制操作与屏幕刷新率同步(60/90/120Hz) - 避免界面撕裂和卡顿 3. **doTraversal()** - VSYNC信号到达后执行`mTraversalRunnable`: ```java final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } ``` - 核心操作: ```java void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; // 移除同步屏障 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); // 执行真正的绘制流程 performTraversals(); } } ``` [^3] 4. **performTraversals()** - 整个绘制流程的核心入口(约1000行代码) - 按顺序执行三大流程: ```java private void performTraversals() { // 1. 测量阶段 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); // 2. 布局阶段 performLayout(lp, mWidth, mHeight); // 3. 绘制阶段 performDraw(); } ``` [^1][^3] #### 三、三大流程详解 1. **performMeasure()** - 计算视图尺寸 - 调用链:`measure()` → `onMeasure()` → `setMeasuredDimension()` - 可能递归调用多次(如WRAP_CONTENT时) 2. **performLayout()** - 确定视图位置 - 调用链:`layout()` → `onLayout()`(ViewGroup中遍历布局子视图) - 触发位置变化回调`onSizeChanged()` 3. **performDraw()** - 执行实际绘制 - 关键调用链: ```java private void performDraw() { draw(fullRedrawNeeded); → drawSoftware() → mView.draw(canvas) // 触发View系统的绘制流程 } ``` [^5] #### 四、同步屏障(Sync Barrier)机制 1. **作用**:确保UI操作优先于常规消息执行 2. **实现原理**: ```java // 设置屏障(postSyncBarrier) MessageQueue.postSyncBarrier() // 移除屏障(removeSyncBarrier) MessageQueue.removeSyncBarrier(token) ``` 3. **重要性**:防止非UI任务阻塞绘制流程,保证16ms内完成绘制(60FPS) #### 五、性能优化设计 1. **合并请求**:同一帧内多次调用`scheduleTraversals()`只会触发一次VSYNC回调 2. **延迟计算**:通过`ViewTreeObserver`注册`OnPreDrawListener`实现布局前计算 3. **硬件加速**:通过`Surface.lockCanvas()`获取画布,直接操作显存[^5] > **关键设计思想**:Android通过VSYNC信号将绘制操作与屏幕刷新率同步,结合同步屏障机制确保UI操作的优先级,最终在`performTraversals()`中完成测量-布局-绘制的完整流程[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值