浅谈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绘制有了更生动的理解?

相关推荐
HLC++10 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼14 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼14 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
壮哥_icon15 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户693717500138416 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记16 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求
吐了啊取名字太难17 小时前
美颜系统AI修图本地跑并支持Mac、win、安卓、iOS不卡顿
android·人工智能·windows·数码相机·mac·ai编程
阿pin18 小时前
Android随笔-Retrofit
android·retrofit
想取一个与众不同的名字好难18 小时前
安卓自定义颜色选择器
android
我命由我1234519 小时前
Android 开发问题:java.lang.NoSuchMethodError:No virtual method readAllBytes()
android·java·java-ee·kotlin·android studio·android-studio·android runtime