Flutter三棵树的构建流程

本文详细阐述了Flutter中Widget、Element和Render对象的家族成员,以及它们之间的创建和关联。从根节点RenderView的创建到MyApp、MyHomePage和ErrorWidget等子节点的构建过程,揭示了Flutter应用的构建流程。在Element的驱动下,Widget对象被保存到对应的Element上,形成逻辑上的虚拟树结构,而Render节点则在需要时被创建并插入到Render树中。整个过程展示了Flutter框架如何将逻辑结构转化为实际的渲染结构。

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

一、Flutter常见的家族成员

  1. Widget常见的家族成员

在这里插入图片描述

  1. Element常见的家族成员

在这里插入图片描述

  1. Render常见的家族成员

在这里插入图片描述

二、示例代码对应的Flutter Inspector树

示例代码:MyApp->MyHomePage->ErrorWidget,包含了StatelessWidget、StatefulWidget、LeafRenderObjectWidget,其中StatelessWidget、StatefulWidget都属于组合Widget,它们通过build或者state.build返回自己的子节点,最后一级的ErrorWidget是LeafRenderObjectWidget,是个叶子节点,它下面没有子节点。

在这里插入图片描述

三、Flutter树根节点的创建和关联

在这里插入图片描述

从上图的创建流程可知,根节点RenderView是在RendererBinding初始化的时候创建的,创建时机最早,接下来调用WidgetsBinding.attachRootWidget方法创建Widget的根节点RenderObjectToWidgetAdapter对象,并把开发者自定义的根Widget MyApp挂载到RenderObjectToWidgetAdapter下面,接下来调用RenderObjectToWidgetAdapter.attachToRenderTree方法创建对应的RenderObjectToWidgetElement对象,这个对象就是Element树的根节点,在创建RenderObjectToWidgetElement对象时通过构造方法持有了RenderObjectToWidgetAdapter对象,然后调用RenderObjectToWidgetElement.mount方法持有了RenderView对象。这样Element就同时持有了其对应的Widget、Render。

四、Flutter树子节点的创建和关联

  1. MyApp层级

在这里插入图片描述

在RenderObjectToWidgetElement.mount方法里,会继续调用RenderObjectToWidgetElement_rebuild->Element.updateChild->Element.inflateWidget,创建MyApp对应的StatelessElement对象,然后将该对象通过updateChild方法返回给上一级Element的子节点,在创建Element对象时通过构造方法持有了MyApp对象,这样Element就持有了Widget。MyApp是StatelessWidget不是RenderObjectWidget,所以MyApp没有对应的createRenderObject方法,StatelessElement是ComponentElement不是RenderObjectElement,其mount方法里也不会调用widget的createRenderObject方法,所以在这个层级,只有Widget节点(MyApp)和与其对应的Element节点(StatelessElement对象),没有对应的Render节点。

  1. MyHomePage层级

在这里插入图片描述

在创建完MyApp对应的StatelessElement方法后,会调用其mount方法,然后经过一系列的方法调用,会调用到StatelessElement的build方法,然后调用MyApp的build方法,在这个build方法里会创建MyHomePage对象并返回,然后将MyHomePage作为参数继续调用Element.updateChild->Element.inflateWidget,然后创建MyHomePage对应的StatefulElement对象,然后将该对象通过updateChild方法返回给上一级Element的子节点,在创建Element对象时通过构造方法持有了MyHomePage对象,这样Element就持有了Widget。MyHomePage是StatefulWidget不是RenderObjectWidget,所以MyHomePage没有对应的createRenderObject方法,StatefulElement是ComponentElement不是RenderObjectElement,其mount方法里也不会调用widget的createRenderObject方法,所以在这个层级,只有Widget节点(MyHomePage)和与其对应的Element节点(StatefulElement对象),没有对应的Render节点。

  1. ErrorWidget层级

在这里插入图片描述

在创建完MyHomePage对应的StatefulElement方法后,会调用其mount方法,然后经过一系列的方法调用,会调用到StatefulElement的build方法,然后调用_MyHomePageState的build方法,在这个build方法里会创建ErrorWidget对象并返回,然后将ErrorWidget作为参数继续调用Element.updateChild->Element.inflateWidget,然后创建ErrorWidget对应的LeafRenderObjectElement对象,然后将该对象通过updateChild方法返回给上一级Element的子节点,在创建Element对象时通过构造方法持有了ErrorWidget对象,这样Element就持有了Widget。LeafRenderObjectElement是RenderObjectElement,会调用ErrorWidget的createRenderObject方法创建renderObject对象(RenderErrorBox),然后将RenderErrorBox对象赋值给Element的_renderObject变量保存下来,然后调用attachRenderObject方法将renderObject插入到Render树里,同时Element也持有了Render对象。

LeafRenderObjectElement是叶子节点类型的Element,没有子节点了,调用mount创建完对应的Render后,执行就结束了,没有后续子节点的创建调用流程了,整个树的创建流程到这里就结束了,各级对应的Widget、Element、Render节点都创建关联完成。

五、示例代码生成的树结构

在这里插入图片描述

从上面的创建过程可知,整棵树的创建过程都是在Element的驱动下进行的,对于有子节点的Element,会递归调用Element.mount->Element.updateChild->Element.inflateWidget->创建下一级的Element对象->Element.mount->…递归循环创建整棵树。

在调用mount的过程如果ELement是RenderObjectElement类型的,还会为其创建对应的Render节点。

在整棵树的创建过程中发现,Widget对象创建完成后是保存到对应的Element上的,不会保存到上一级Widget上,Widget是没有直接的父子关系的,Widget这颗树可以理解为是虚拟的,是逻辑上存在的,它的树结构是通过Element实体树来反映的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值