Android随笔-view是如何显示到屏幕上

面显示在屏幕上的完整链路,从 View 的 measure/layout/draw 到 SurfaceFlinger 合成 再到 LCD 像素发光 ,共经历 8 个阶段。

一、整体链路

二、Stage 1: View 体系 --- measure / layout / draw

这是应用开发最熟悉的部分,但发生在应用进程中

2.1 View 树结构

2.2 三大遍历

方法 作用 关键类
measure() 确定自身及子 View 的宽高 MeasureSpec (EXACTLY / AT_MOST / UNSPECIFIED)
layout() 确定自身及子 View 的位置 (left/top/right/bottom) ViewGroup.onLayout()
draw() 在 Canvas 上绘制内容 Canvas.drawText() / drawBitmap() / drawRect()

2.3 源码入口

java 复制代码
// ViewRootImpl.java --- 核心入口
private void performTraversals() {
    // 1. MEASURE
    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    // -> DecorView.onMeasure() -> 递归测量所有子 View
    
    // 2. LAYOUT
    performLayout(lp, desiredWindowWidth, desiredWindowHeight);
    // -> DecorView.onLayout() -> 递归布局所有子 View
    
    // 3. DRAW
    performDraw();
    // -> 从 Surface 获取 Canvas -> DecorView.draw() -> 递归绘制
}

三、Stage 2: ViewRootImpl --- 连接 View 与 SurfaceFlinger 的桥梁

3.1 ViewRootImpl 的核心作用

功能 说明
setView() 建立与 WMS 的连接,创建 Surface,启动 Choreographer
Choreographer 同步 VSync 信号(60Hz 每 16.67ms 触发一次),驱动 doFrame()
Surface 图形缓冲区句柄,应用在上面绘制,SF 合成它
SurfaceControl WMS 通过 SurfaceFlinger 创建,应用获得引用用于绘制

3.2 绘制提交

java 复制代码
// ViewRootImpl.performDraw()
private void performDraw() {
    // 1. 从 Surface 获取 Canvas
    Canvas canvas = mSurface.lockHardwareCanvas();
    // 硬件加速:lockHardwareCanvas() → OpenGL ES 后端
    // 软件渲染:lockCanvas() → Bitmap 后端
    
    // 2. 绘制整个 View 树
    mView.draw(canvas);  // DecorView.draw()
    // -> ViewGroup.dispatchDraw() → 每个子 View 的 draw()
    // -> TextView.onDraw(): canvas.drawText()
    // -> ImageView.onDraw(): canvas.drawBitmap()
    
    // 3. 提交缓冲区给 SurfaceFlinger
    mSurface.unlockCanvasAndPost(canvas);
    // -> queueBuffer() 到 BufferQueue
    // -> SurfaceFlinger 收到新缓冲区就绪通知
}

四、Stage 3: BufferQueue --- 生产者-消费者模型

每个 Surface 对应一个 BufferQueue,应用是生产者SurfaceFlinger 是消费者

Triple Buffering(三缓冲):

  • Front Buffer:正在显示
  • Back Buffer:SF 正在合成
  • Free Buffer:App 正在绘制

三缓冲防止 App 绘制和 SF 合成互相阻塞。

五、Stage 4: SurfaceFlinger --- 图层合成

5.1 SurfaceFlinger 的职责

  • 收集所有应用的 Surface(Layer)
  • 按 Z-Order 排序
  • 合成(Composite)为单一帧缓冲区
  • 通过 HWComposer 提交到显示硬件

5.2 合成流程

java 复制代码
// SurfaceFlinger::onMessageReceived()
void SurfaceFlinger::onMessageReceived(int32_t what) {
    // 1. VSync 到达
    // 2. 收集所有有新缓冲区的 Layer
    for (const auto& layer : mLayers) {
        if (layer->hasNewBuffer()) {
            layer->updateTexImage();  // acquire 新缓冲区
        }
    }
    
    // 3. 请求 HWC 合成
    hwcDevice->setDisplayContents(display, layers);
    
    // 4. 如果 HWC 能处理所有 Layer → 硬件 overlay 合成
    //    如果不能 → GPU 通过 OpenGL 合成剩余 Layer
    
    // 5. 提交到显示
    hwcDevice->presentDisplay(display);
}

5.3 合成方式

方式 说明 性能
HWC Overlay 硬件直接把 Layer 送到显示控制器,绕过 GPU 最优,零 GPU 开销
GPU Composition GPU 把所有 Layer 合成到一个 framebuffer 耗电,但兼容性好
Mixed HWC 处理部分 Layer,GPU 处理剩余 平衡

六、Stage 5: VSync 与帧率控制

6.1 VSync 机制

概念 说明
VSync 显示器垂直同步信号,60Hz 屏幕每 16.67ms 发一次
Choreographer App 注册 doFrame() 回调,VSync 到达时触发
Jank(掉帧) App 绘制超过 16ms,错过 VSync → 重复显示上一帧

6.2 时序示例

bash 复制代码
VSync 0:  App 绘制 Frame 0  ──> SF 合成 Frame 0  ──> 显示 Frame 0
VSync 1:  App 绘制 Frame 1  ──> SF 合成 Frame 1  ──> 显示 Frame 1
VSync 2:  App 绘制 Frame 2 (慢) 
VSync 3:  App 还在画 Frame 2  ──> SF 合成 Frame 1  ──> 显示 Frame 1 (JANK!)
VSync 4:  App 完成 Frame 2  ──> SF 合成 Frame 2  ──> 显示 Frame 2

七、Stage 6: 显示硬件 --- 从 Framebuffer 到像素发光

7.1 硬件链路

组件 作用
Framebuffer 最终合成图像在内存中的存储
Display Controller 硬件读取 framebuffer,通过 DSI/MIPI 发送给 LCD 面板
LCD Panel 物理像素:TFT 控制液晶偏转 + RGB 滤光片 + LED 背光
OLED Panel 每个像素自发光(R/G/B 子像素),无背光

7.2 LCD vs OLED

特性 LCD OLED
发光原理 背光穿透液晶 + 滤色片 有机材料自发光
对比度 有背光漏光,对比度低 纯黑像素不发光,对比度无限
响应速度 液晶偏转慢,有拖影 纳秒级响应
功耗 背光常亮,功耗固定 暗色场景功耗低
寿命 有机材料老化,可能烧屏

八、特殊渲染路径

类型 特点 适用场景
普通 View 走完整 measure/layout/draw,硬件加速 大多数 UI
TextureView 渲染到 OpenGL Texture,支持变换 视频播放、Camera 预览
SurfaceView 独立 Surface,绕过 View 层级,直接到 SF 游戏、视频(性能最优)
WebView 独立 Surface + GPU 进程 网页内容
Compose 直接操作 Canvas,无 View 层级 Jetpack Compose UI

九、完整链路总结

阶段 所在进程 核心操作 输出
1. measure App View.measure() 递归计算宽高 每个 View 的 measuredWidth/Height
2. layout App View.layout() 递归确定位置 每个 View 的 left/top/right/bottom
3. draw App View.draw() 递归绘制到 Canvas 图形缓冲区(Buffer)
4. submit App unlockCanvasAndPost()queueBuffer() Buffer 进入 BufferQueue
5. acquire SurfaceFlinger acquireBuffer() 获取新缓冲区 Layer 更新
6. composite SurfaceFlinger 合成所有 Layer 到 framebuffer 最终帧图像
7. present HWComposer presentDisplay() 提交到显示控制器 显示控制器读取
8. display Hardware 像素发光 人眼看到图像
相关推荐
恋猫de小郭2 小时前
Flutter material/cupertino 解耦最新进展,已经在做新样式了
android·前端·flutter
在书中成长2 小时前
HarmonyOS 小游戏《对战五子棋》开发第17篇 - AI的两种评估策略
android·java·javascript
私人珍藏库2 小时前
[Android] Npatch-免Root框架+可内置模块
android·人工智能·智能手机·工具·软件
黄林晴3 小时前
KMP 正式支持 SwiftPM:CocoaPods 迁移配置指南
android·ios·kotlin
AFinalStone3 小时前
Android 7系统网络(二)内核层—netfilter_iptables与路由策略
android·网络
吠品3 小时前
Mac定时关机、开机自动化:用shutdown和pmset就够了
android·java·开发语言
2601_9637713719 小时前
Offloading WP-Cron and Securing Ticket Webhooks on Enterprise IT Sites
android
花燃柳卧19 小时前
跨平台路由组件工程源码补充上传
android·flutter·kotlin
apihz19 小时前
随机驾考题目(C 照科一 / 科四 2000+ 题)免费API调用教程
android·java·c语言·开发语言·网络协议·tcp/ip