Skip to content

渲染三棵树原理

ArkUI 的渲染引擎核心:逻辑树 → 渲染树 → 节点树(LayerTree/RSNode)。


1. 渲染三棵树概览

用户操作(点击/状态变化)

【第一棵:逻辑树 ViewTree】
   ArkUI 框架层
   - 组件描述
   - 状态管理
   - 数据绑定
    ↓ Diff
【第二棵:渲染树 RenderTree】
   ArkUI RenderService
   - 布局计算(Layout/Measure)
   - 样式计算
   - 节点树生成

【第三棵:节点树 LayerTree/RSNode】
   Render Service / GPU
   - 绘制(Draw)
   - 合成(Composition)
   - 显存管理

屏幕显示

2. 第一棵:逻辑树(ViewTree)

2.1 职责

逻辑树是 ArkUI 的UI 描述层,由框架创建和维护:

  • 组件树结构的创建和管理
  • 状态管理(@State/@Prop/@Link 等)
  • Diff 算法对比新旧 UI 描述
  • 生成渲染树变更指令

2.2 生命周期

组件创建 → 逻辑树节点创建

状态变化 → Diff 对比 → 变更标记

渲染树更新 → 变更下发到渲染树

组件销毁 → 逻辑树节点销毁

2.3 Diff 算法

typescript
// 状态变化后,ArkUI 执行 Diff 对比
const oldTree = build()  // 旧的 UI 描述
const newTree = build()  // 新的 UI 描述

// Diff 对比(三层)
for (let i = 0; i < newTree.length; i++) {
    if (newTree[i] === oldTree[i]) {
        // 相同 → 跳过
    } else if (newTree[i].type === oldTree[i].type) {
        // 类型相同 → 对比属性,更新变化的属性
    } else {
        // 类型不同 → 删除旧节点,创建新节点
    }
}

3. 第二棵:渲染树(RenderTree)

3.1 职责

渲染树是 ArkUI 的布局计算层

  • 执行 Measure(测量)→ Layout(布局)→ Draw(绘制)
  • 坐标系统计算
  • 层合并(Layer Merging)优化
  • 渲染指令生成

3.2 渲染流程

1. Measure(测量)
   - 计算每个节点需要的尺寸
   - 从叶子节点向根节点传递(Bottom-up)

2. Layout(布局)
   - 根据测量结果确定每个节点的位置
   - 从根节点向叶子节点传递(Top-down)

3. Draw(绘制)
   - 生成绘制指令
   - 传递给渲染服务(RenderService)

3.3 层合并(Layer Merging)优化

未合并:
┌─────┐  ┌─────┐  ┌─────┐
│ Text │  │Text │  │Text │
└─────┘  └─────┘  └─────┘
(3 个渲染层)

层合并后:
┌─────────────────┐
│ Text Text Text  │
└─────────────────┘
(1 个渲染层)

效果:减少 GPU 层数,提升渲染性能

4. 第三棵:节点树(LayerTree/RSNode)

4.1 职责

节点树是渲染服务层(RenderService),直接操作 GPU:

  • FrameNode → RenderNode 的映射
  • GPU 显存管理
  • 绘制指令执行
  • 图层合成

4.2 FrameNode vs RenderNode

概念层级说明
FrameNodeArkUI 层开发者可见的 UI 组件节点
RenderNodeRenderService 层底层渲染对象,不可见
ArkUI 层                    RenderService 层
FrameNode (UI节点)    →    RenderNode (渲染对象)
FrameNode (UI节点)    →    RenderNode (渲染对象)
    ↓                        ↓
Diff 对比 (ArkUI)      变更下发 (RenderService)
    ↓                        ↓
Measure/Layout/Draw   →    GPU 绘制 → 合成 → 屏幕

5. 渲染优化的核心思路

5.1 减少不必要的重建

❌ 触发全量重建:
├─ 修改了根节点的 @State
├─ build() 中嵌套太深(Diff 开销大)
└─ 频繁创建/销毁组件节点

✅ 局部刷新:
├─ 修改局部 @State(只重建该节点及其子树)
├─ 使用 LazyForEach(按需渲染)
└─ 组件提取复用(减少 Diff 范围)

5.2 减少层数

✅ 减少层数的方法:
├─ 合并相邻相同样式的文本(层合并)
├─ 使用固定宽高(避免 Measure 重复计算)
├─ 减少嵌套深度(降低布局计算量)
└─ 使用图片下采样(减少显存占用)

5.3 渲染三棵树性能影响

| 优化点 | 影响哪棵树 | 效果 | |---|-|-|--| | 固定宽高 | 第二棵(RenderTree) | 避免重复 Measure | | 减少嵌套 | 第一棵 + 第二棵 | 减少 Diff + 布局开销 | | LazyForEach | 第二棵 + 第三棵 | 按需创建渲染层 | | 图片下采样 | 第三棵(LayerTree) | 减少显存占用 | | 层合并 | 第三棵(LayerTree) | 减少 GPU 层数 |


6. 面试高频考点

Q1: 渲染三棵树分别是什么?

回答

  1. 逻辑树(ViewTree):UI 描述层,包含组件树和状态管理,执行 Diff 对比
  2. 渲染树(RenderTree):布局计算层,执行 Measure → Layout → Draw
  3. 节点树(LayerTree/RSNode):渲染服务层,映射到 GPU,执行绘制和合成

Q2: FrameNode 和 RenderNode 的区别?

回答:FrameNode 是 ArkUI 层开发者可见的 UI 节点,RenderNode 是 RenderService 层底层渲染对象。FrameNode 通过 Diff 对比生成变更指令,传递给 RenderNode 执行。

Q3: 层合并(Layer Merging)的作用?

回答:将相邻相同样式的组件合并为同一个渲染层,减少 GPU 层数,提升渲染性能。


🐱 小猫提示:渲染三棵树是鸿蒙面试中最硬核的原理题。记住:ViewTree(Diff)→ RenderTree(Measure/Layout/Draw)→ LayerTree(GPU绘制/合成)。面试中能画出来就稳了。