从Activity.setContentView()开始

一、从 Activity.setContentView() 开始的调用链

scss 复制代码
Activity.setContentView(layoutId)
    ↓
PhoneWindow.setContentView(view)
    ↓
创建 / 装配 DecorView
    ↓
WindowManager.addView(DecorView, params)
    ↓
WindowManagerGlobal.addView(...)
    ↓
new ViewRootImpl(...)
    ↓
ViewRootImpl.setView(DecorView, params)
    ↓
requestLayout() → scheduleTraversals()
    ↓
doTraversal() → performMeasure() / performLayout() / performDraw()
    ↓
View 树 onDraw(Canvas)
    ↓
Canvas → Skia → (OpenGL ES / 软件渲染)
    ↓
绘制到 Surface 的 Buffer

二、Activity, Window, DecorView:界面"外壳结构"

Activity:逻辑入口 + 拥有一个 Window

  • 每个 Activity 内部都持有一个 Window(通常是 PhoneWindow)。
  • 当你调用:setContentView(R.layout.activity_main);

其实是

less 复制代码
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID); // 交给 PhoneWindow
}

Window / PhoneWindow:管理 DecorView 的"窗口对象"

  • Window 是一个抽象类,PhoneWindow 是常见实现。

  • 它负责:

    • 创建并管理 DecorView(整个窗口的根视图);
    • 处理标题栏、状态栏适配等"窗口装饰"。

简化的调用链:

scss 复制代码
Activity.setContentView()
    └─ PhoneWindow.setContentView()
            ├─ ensureDecor()  // 确保 DecorView 已创建
            │     └─ installDecor()
            │          └─ mDecor = new DecorView(...)
            └─ 将 layoutId inflate 成 View,并添加到 mDecor 的 content 区域

DecorView & View / ViewGroup:UI 树结构

  • DecorView:

    • 继承自 ViewGroup;
    • 是当前 Window 的 根 View;
    • 内含状态栏/标题栏区域 + 内容区域。
  • XML 布局最终会成为:

scss 复制代码
DecorView (FrameLayout)
    └─ contentParent (id=android.R.id.content)
          └─ 你的根 ViewGroup (例如 ConstraintLayout)
                └─ 若干子 View / ViewGroup

这些 View/ViewGroup 负责在三大阶段中工作:

  • onMeasure():计算大小;
  • onLayout():确定位置;
  • onDraw(Canvas):在 Canvas 上画出自己。

这一切目前 还只是在内存结构上建立,还没有真正"出现在屏幕上"。

三、WindowManager / WMS / ViewRootImpl:把 DecorView 挂到窗口 & Surface 上

WindowManager:应用侧窗口管理接口

  • Activity 内可以调用 getWindowManager() 或使用 WindowManager 添加/更新 View(如 Dialog、Toast)。
  • 当 PhoneWindow.setContentView() 完成 DecorView 构造后,Activity/系统会调用:
ini 复制代码
WindowManager wm = getWindowManager();
wm.addView(decorView, layoutParams);

WindowManagerGlobal / ViewRootImpl:建立与 WMS 的连接

WindowManager.addView() 内部最终走到:

scss 复制代码
WindowManagerGlobal.addView(view, params)
    ├─ 创建 ViewRootImpl root = new ViewRootImpl(context, display)
    ├─ root.setView(view, params)
    └─ 记录 (view ↔ root) 映射关系

此时几个关键点:

  • ViewRootImpl 被创建;
  • DecorView 被交给 ViewRootImpl 管理;
  • ViewRootImpl 通过 Binder 与 WMS(WindowManagerService) 通信,申请窗口、布局、Surface 等。

WMS(WindowManagerService):系统级窗口管理

在 系统进程 中运行,统一管理所有 app 的窗口:

  • 决定窗口的位置、尺寸、Z 轴顺序;
  • 为窗口分配/更新对应的 Surface;
  • 将窗口信息提供给 SurfaceFlinger 刷新显示。

关系图(结构视角):

scss 复制代码
[ Activity ]
    └─ [ Window (PhoneWindow) ]
            └─ [ DecorView (ViewGroup 根) ]
                    ↑
                    │ setContentView()
                    │
[ WindowManagerImpl ] (App进程)
    └─ [ WindowManagerGlobal ]
            └─ new ViewRootImpl(...)
                    └─ setView(DecorView, params)
                           ↕ Binder
                     [ WMS (系统进程) ]
                           └─ 管理 Window、分配 Surface

四、Surface:ViewRootImpl 与图形系统的"接缝处"

Surface:底层缓冲队列的 Java 封装

  • 每个 Window 在 WMS/SurfaceFlinger 侧都会有一个 Surface 对应;

  • 对 ViewRootImpl 来说,它持有一个 Surface mSurface:

    • 这是它绘制输出的目标;
    • 内部与 BufferQueue 关联,生产者是当前窗口(App 侧),消费者是 SurfaceFlinger。

ViewRootImpl.setView() & requestLayout()

ViewRootImpl.setView() 完成:

  • 保存根 View = DecorView;
  • 向 WMS 注册窗口;
  • 初始化 Surface;
  • 调用 requestLayout(),触发第一次测量/布局/绘制。

requestLayout() 内部最终会走到:

scss 复制代码
ViewRootImpl.requestLayout()
    └─ scheduleTraversals()
           └─ mChoreographer.postCallback(TRAVERSAL, mTraversalRunnable, ...)

这里就引出了 Choreographer。

五、Choreographer + Handler:VSync 驱动的 UI 刷新

Handler / Looper:消息循环基础

  • UI 线程拥有 Looper + MessageQueue;

  • Handler 用来:

    • 发送消息、投递 Runnable;
    • 在 UI 线程执行各种回调(包括 ViewRootImpl 的刷新逻辑)。

Choreographer:基于 VSync 的帧调度器

  • Choreographer 挂在 UI 线程上;

  • scheduleTraversals() 会通过 Choreographer 在 下一个 VSync 时 执行 doTraversal(),而不是立刻执行:

    • 这样能保证所有 requestLayout()/invalidate() 合并到下一帧统一处理;
    • 避免"抖动"和无意义重复绘制。

简化版时序:

scss 复制代码
requestLayout() / invalidate()
    ↓
ViewRootImpl.scheduleTraversals()
    ↓
Choreographer.postCallback(TRAVERSAL, doTraversal)
    ↓   (等到下一次 VSync)
Choreographer#doFrame()
    └─ doTraversal()  // 核心渲染流程

六、ViewRootImpl.doTraversal():三大流程 + Canvas / Skia / OpenGL ES

doTraversal() 里会顺序执行:

scss 复制代码
performMeasure() → performLayout() → performDraw()

performMeasure()

  • 从 DecorView 开始向下:

    • 调用每个 View / ViewGroup 的 onMeasure();
    • 计算 width/height。

performLayout()

  • 对根 View 调用 layout(l, t, r, b):

    • ViewGroup 会在 onLayout() 中安排子 View 的位置;
    • 整个树的几何结构确定。

performDraw():真正的绘制

核心逻辑类似:

typescript 复制代码
public void performDraw() {
    // 省略前置逻辑
    draw(fullRedrawNeeded);
}

private void draw(boolean fullRedrawNeeded) {
    // 获取/准备 Canvas
    // 调用 DecorView.draw(canvas)
}

调用链:

scss 复制代码
ViewRootImpl.performDraw()
    └─ DecorView.draw(Canvas)
          └─ drawBackground()
          └─ onDraw(Canvas)
          └─ dispatchDraw(Canvas)  // 调子 View 的 draw()
                 └─ 每个子 View 的 onDraw(Canvas)

Canvas / Skia / OpenGL ES

在 onDraw(Canvas) 中,开发者用 Canvas 提供的 API 绘制:

css 复制代码
protected void onDraw(Canvas canvas) {
    canvas.drawRect(...);
    canvas.drawText(...);
    canvas.drawBitmap(...);
}

底层发生了:

arduino 复制代码
Canvas API
    ↓
Skia (2D 引擎)
    ↓
※ 若软件渲染:在 CPU 内存 buffer 中画像素
※ 若硬件加速(HWUI + OpenGL ES/Vulkan):
       Skia 将绘制指令转换为 GPU 命令
           ↓
       通过 OpenGL ES / Vulkan 调 GPU 渲染
           ↓
       GPU 把结果写入当前 Surface 的 buffer
相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui