浅谈View经GPU渲染绘制的过程

咱们今天就用一个超有趣的故事来理解Android的View绘制原理。准备好了吗?

故事开始:UI王国的"画展"筹备记

想象一下,Android系统就像一个庞大的UI王国,每次打开App就像举办一场画展。

角色介绍:

  • ViewRootImpl:画展总策划(大管家)
  • DecorView:画展的巨型画布
  • View/ViewGroup:各种画家和画师小组
  • Choreographer:动画导演(负责节奏)
  • SurfaceFlinger:最终展厅布置师
  • CPU/GPU:画家们的双手

第一幕:画展的启动(Activity创建)

java 复制代码
// 王国收到举办画展的指令
public class Activity {
    public void onCreate() {
        setContentView(R.layout.main); // "准备画布和颜料!"
    }
}

当Activity创建时,PhoneWindow会准备DecorView这个"巨型画布",然后通过LayoutInflater把XML布局变成一个个View对象。

第二幕:三大核心流程 - 画展筹备三部曲

1. 测量(Measure)- "量尺寸"

总策划ViewRootImpl大喊:"各位画家,报上你们的尺寸!"

java 复制代码
// ViewRootImpl.java
private void performTraversals() {
    // 第一步:测量
    performMeasure();
    // 第二步:布局
    performLayout();
    // 第三步:绘制
    performDraw();
}

// 测量过程 - 递归测量所有View
private void performMeasure() {
    int childWidthMeasureSpec = ...;
    int childHeightMeasureSpec = ...;
    mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

每个View的measure方法:

java 复制代码
// View.java
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    onMeasure(widthMeasureSpec, heightMeasureSpec); // 自定义测量逻辑
    // 测量完成后,mMeasuredWidth/mMeasuredHeight就有值了
}

有趣比喻:就像画家们互相商量:"我要占多大地方?你有多宽?我有多高?"

2. 布局(Layout)- "定位置"

"现在开始布置展位!每个人站在哪里?"

java 复制代码
// ViewGroup.java
@Override
public final void layout(int l, int t, int r, int b) {
    // 先确定自己的位置
    super.layout(l, t, r, b);
    // 再安排子View的位置
    layoutChildren();
}

protected void layoutChildren() {
    for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        // 计算每个子View的位置
        child.layout(childLeft, childTop, childRight, childBottom);
    }
}

3. 绘制(Draw)- "动笔作画"

"各就各位,开始画画!"

java 复制代码
// View.java
public void draw(Canvas canvas) {
    // 步骤1:画背景
    drawBackground(canvas);
    // 步骤2:画自己(核心)
    onDraw(canvas);
    // 步骤3:画子View
    dispatchDraw(canvas);
    // 步骤4:画装饰(滚动条、前景等)
    onDrawForeground(canvas);
}

第三幕:同步与渲染 - 动画导演登场

Choreographer(动画导演)负责保持60fps的流畅节奏:

java 复制代码
// Choreographer.java
public void onVsync() {
    // 垂直同步信号到来!
    mHandler.post(mTraversalRunnable);
}

final class TraversalRunnable implements Runnable {
    public void run() {
        doTraversal(); // 执行遍历(测量-布局-绘制)
    }
}

第四幕:硬件加速 - GPU大神出手

现代Android使用硬件加速,就像请来了GPU这位"神笔马良":

java 复制代码
// ThreadedRenderer.java(硬件渲染器)
@Override
void draw(View view, AttachInfo attachInfo) {
    // 1. 创建DisplayList(绘制指令列表)
    updateRootDisplayList(view);
    // 2. 同步到RenderThread
    nSyncAndDrawFrame(mNativeProxy);
}

DisplayList就像给GPU的"绘画说明书",避免重复计算。

第五幕:最终展示 - SurfaceFlinger布展

cpp 复制代码
// SurfaceFlinger.cpp(Native层)
void SurfaceFlinger::composite() {
    // 收集所有Layer(图层)
    for (auto layer : mLayers) {
        layer->latchBuffer(); // 获取图形缓冲区
        layer->prepareClientComposition(); // 准备合成
    }
    // 最终合成并显示
    doComposition();
    postFramebuffer(); // 输出到屏幕
}

完整时序图:画展全流程

关键技巧:性能优化秘诀

  1. 减少层级:画展布置不要太复杂(View层级扁平化)
  2. 避免过度绘制:不要在同一区域反复画画
  3. 使用硬件加速:让GPU大神多干活
  4. View复用:像 recyclerView 一样,重复利用画布
java 复制代码
// 优化示例:自定义View避免无效重绘
@Override
protected void onDraw(Canvas canvas) {
    if (needRedraw) { // 只有需要时才重绘
        drawContent(canvas);
        needRedraw = false;
    }
}

总结:一场精密的协作

Android View的绘制就像一场精心组织的画展:

  • ViewRootImpl是总策划,协调整个流程
  • 测量-布局-绘制是核心三部曲
  • Choreographer保证60fps的流畅节奏
  • GPU硬件加速提供强大的绘制能力
  • SurfaceFlinger是最终的舞台总监

理解了这套机制,你就能写出更流畅的UI,成为真正的Android UI大师!

怎么样,同学,现在是不是对View绘制有了更生动的理解?

相关推荐
南宫码农16 分钟前
我的电视 - Android原生电视直播软件 完整使用教程
android·开发语言·windows·电视盒子
道亦无名29 分钟前
音频数据特征值提取 方法和步骤
android·音视频
Lancker44 分钟前
定制侠 一个国产纯血鸿蒙APP的诞生过程
android·华为·智能手机·鸿蒙·国产操作系统·纯血鸿蒙·华为鸿蒙
2601_949809592 小时前
flutter_for_openharmony家庭相册app实战+通知设置实现
android·javascript·flutter
液态不合群3 小时前
【面试题】MySQL 中 count(*)、count(1) 和 count(字段名) 有什么区别?
android·数据库·mysql
雪球Snowball4 小时前
【Android关键流程】资源加载
android
2501_915918414 小时前
常见 iOS 抓包工具的使用,从代理抓包、设备抓包到数据流抓包
android·ios·小程序·https·uni-app·iphone·webview
墨月白6 小时前
[QT]QProcess的相关使用
android·开发语言·qt
enbug7 小时前
编译安卓内核:以坚果R1、魔趣MK100(Android 10)系统为例
android·linux
、BeYourself7 小时前
应用专属文件与应用偏好设置(SharedPreferences)
android