Flutter渲染原理

Flutter的渲染流程涉及Vsync同步、UI线程、GPU图层合成及Skia引擎。核心操作在UIThread中,包括动画、构建、布局和绘制阶段。Flutter通过Widgets、Elements和RenderObjects的三棵树机制实现高效渲染,减少不必要的重建和提高性能。Element作为Widget和RenderObject的桥梁,仅在Widget变化时更新RenderObject配置,降低性能开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
上图的渲染流程:GPU的Vsync信号同步到UI线程,UI线程使用Dart来构建抽象的视图结构,绘制好的抽象视图数据结构在GPU线程中进行图层合成,然后提供给Skia引擎渲染GPU数据,最后通过OpenGL或者Vulkan提供给GPU。可以发现,渲染的核心在UI Thread中,在UI Thread中Flutter框架会做如下操作:

  • 动画(Animate)阶段:因为动画会随每个Vsync信号的到来而改变状态(State),所以动画阶段是流水线的第一个阶段;
  • 构建(Build)阶段:需要被构建的Widget会在此阶段被构建,对应的函数StatelessWidget.build()或者State.build()被调用的时候;
  • 布局(Layout)阶段:会确定各个元素的位置、尺寸,对应的RenderObject.performLayout()被调用的时候;
  • 绘制(Paint)阶段:RenderObject.paint()被调用的时候;

Flutter如何实现高效渲染的

通过Flutter提供的Widgets,我们可以构造出各种界面,那这些Widgets是如何工作的,这就涉及到三棵树渲染机制了。
在Flutter中和Widgets相关的,还有Elements和RenderObjects,由于它们都具有树形结构,所以被称作三棵树。

  • Widget:Widget是Flutter的核心部分,是用户界面的不可变部分;
  • Element:Element是实例化的Widget对象,通过Widget的createElement()方法,是在特定位置使用Widget配置数据生成;
  • RenderObject:用于应用界面的布局和绘制,保存了元素的大小、布局等信息;

runApp(const HuApp());被调用时,会发生如下几个阶段:

  • Flutter会构建包含页面HuApp和其子节点的Widgets树;
  • Flutter遍历Widget树,然后根据其中的Widget调用createElement()来创建相应的Element对象,最后将这些对象组建成Element树;
  • 接下来会创建第三个树,这个树包含了与Widget对应的Element通过createRenderObject()创建的RenderObject;
    Flutter经过这三个步骤后的状态:
    在这里插入图片描述
    可以看出Element是Widget树和RenderObject树之间的桥梁,每一个Element中都有着对应的Widget和RenderObject的引用。
    当一个页面在刷新时,有些是改变的,有些是不变的。那么三棵树,就是为了避免频繁的创建和销毁不变的部分,以此提高渲染性能。实例化一个RenderObject的成本是很高的,频繁的实例化和销毁RenderObject对性能的影响很大,所以当Widget数改变的时候,Flutter使用Element树来对比新老Widget

('vm:prefer-inline')
Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
  if (newWidget == null) {
    if (child != null) {
      deactivateChild(child);
    }
    return null;
  }
  final Element newChild;
  if (child != null) {
    bool hasSameSuperclass = true;
    assert(() {
      final int oldElementClass = Element._debugConcreteSubtype(child);
      final int newWidgetClass = Widget._debugConcreteSubtype(newWidget);
      hasSameSuperclass = oldElementClass == newWidgetClass;
      return true;
    }());
    ...

  return newChild;
}
  • 如果某个位置的Widget和新Widget不一致,才需要重新创建Element;
  • 如果某个位置的Widget和新Widget一致,则只需要修改RenderObject的配置,不用进行耗费性能的RenderObject重新构建;

在实际开发中,我们接触不到Element,实际上每个Widget的build(BuildContext context)方法中传递的context就是实现了BuildContext接口的Element。

其实在Flutter的这种设定中,Widget类似于配置文件,而最终是通过Element、RenderObject去做的渲染操作。所以Widget并不是真正的干活的,Widget的嵌套事实上并不是View的嵌套,不会造成性能问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值