[摘要版]flutter的渲染基本流程

236 阅读1分钟

Flutter渲染流程和性能优化指南

1. 三棵树的基本关系

  • Widget树 -> Element树 -> RenderObject树
// 示例结构
Widget树: MyWidget -> Container -> Text
Element树: MyWidgetElement -> ContainerElement -> TextElement
RenderObject树: RenderConstrainedBox -> RenderParagraph

2. 更新流程

setState触发的更新链:

  1. markNeedsBuild()
  2. scheduleBuildFor()
  3. BuildOwner.scheduleBuildFor()
  4. WidgetsBinding.drawFrame()
  5. buildScope()

3. 渲染管线(Pipeline)

Build -> Layout -> Paint -> Composite

各阶段工作内容:

  1. Build阶段

    • Widget.build()
    • Element.rebuild()
    • RenderObject.markNeedsLayout()
  2. Layout阶段

    • RenderObject.performLayout()
    • 子Widget.layout()
    • 确定大小和位置
  3. Paint阶段

    • RenderObject.paint()
    • Canvas绘制
    • 生成Layer
  4. Composite阶段

    • Layer树
    • SceneBuilder
    • Scene
    • Window.render()

4. 性能优化策略

4.1 控制重建范围

class MyWidget extends StatefulWidget {
  @override
  bool get runtimeType => false; 
  
  @override
  bool operator ==(Object other) => true; 
}

4.2 分离变与不变

class MyWidget extends StatelessWidget {
  final Widget staticChild = const Text('Static');
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        staticChild,
        _buildDynamicPart(),
      ],
    );
  }
}

4.3 使用GlobalKey精确更新

GlobalKey key = GlobalKey();
Widget child = Container(key: key);

5. 调试技巧

// 打开性能叠加层
debugPaintLayerBordersEnabled = true;

// 检测重建
debugPrint('Building: ${context.widget.runtimeType}');

// 检测布局
debugPrintBeginFrameBanner = true;

// 性能分析
debugProfileBuildsEnabled = true;

6. 核心优化原则

  1. 最小化setState影响范围
  2. 合理使用const构造函数
  3. 善用Key进行细粒度控制
  4. 适当使用RepaintBoundary
  5. 避免频繁重建Widget共享状态

7. StatefulWidget嵌套重建规则

  • setState会重建当前StatefulWidget及其所有子Widget

  • 实际重建受以下因素影响:

    • const构造函数
    • shouldComponentUpdate
    • Flutter的内部优化机制
    • Widget的相等性比较

8. 优化示例

// 1. const构造
const MyWidget()

// 2. RepaintBoundary隔离
RepaintBoundary(
  child: ExpensiveWidget(),
)

// 3. 使用GlobalKey
final key = GlobalKey();
MyWidget(key: key)

9. 注意事项

  • build方法执行不等于实际重建和重绘
  • Flutter会对比新旧Widget树进行优化
  • Element树和RenderObject树的更新才是实际开销所在
  • 合理使用性能分析工具定位问题