和谐学习!不急不躁!!我是你们的老朋友小青龙~
前言
Flutter有三棵树
Widget树
(经常变化)Element树
Render树
(flutter引擎,渲染的是Render树)
不是所有的Widget都会有Render,比如
只有继承自RenderObjectWidget的Widget对象才有Render树
。
RenderObjectWidget
我们看到RenderObjectWidget有两个抽象方法:
RenderObjectElement createElement()
;RenderObject createRenderObject(BuildContext context)
;
从字面意思应该是创建Element、创建RRenderObject。
createElement()
我们在RenderObjectWidget的子类MultiChildRenderObjectWidget
类,发现它实现了createElement方法:
MultiChildRenderObjectElement
继承自RenderObjectElement
createRenderObject(BuildContext context)
我们在【RenderObjectWidget】的子类Flex
类源码里,看到它实现了父类的抽象方法
createRenderObject:
并且看到它返回一个「RenderFlex」类,点进去发现层级关系:
RenderFlex -> RenderBox -> RenderObject
Flex实现父类的抽象方法createRenderObject,创建RenderObject对象并加入到RenderObject树。
即,`只有实现了createRenderObject方法创建了RenderObject对象的widget才会被独立渲染。`
RenderObjectWidget小结
所以我们大致有了这么一个结论:继承自RenderObjectWidget的Widget,会创建三棵树:
Widget树
Element树
Render树
那些没有继承RenderObjectWidget的Widget又会创建什么树呢?
首先Widget树肯定的,毕竟万物皆Widget。
其次,我们找几个Widget:
我们发现,无论是StatelessWidget
还是StatefulWidget
,都会实现createElement
方法,只不过不同的Widget调用createElement方法,返回的类型
不同,即:
-
StatelessWidget
调用createElement方法,返回StatelessElement
类型的Element; -
StatefulWidget
调用createElement方法,返回StatefulElement
类型的Element; -
MultiChildRenderObjectWidget
调用createElement方法,返回MultiChildRenderObjectElement
类型的Element; -
RenderObjectWidget
调用createElement方法,返回RenderObjectElement
类型的Element;
【查看StatelessElement】
【查看StatefulElement】
而我们日常写法如下
都需要通过build方法
来返回一个【最终Widget】,区别是:
-
一个在StatelessElement子类里实现build方法(比如图片里的lesWidget)
-
一个在State类里实现build方法
这刚好对应着前面图片源码里的两行代码:
/// StatelessElement源码
Widget build() => widget.build(this);
/// StatefulElement源码
Widget build() => state.build(this);
所以这就很好的解释了,为什么我们平时写代码的时候,实现StatefulWidget
子类要多实现一个State类
。
【再次查看StatelessElement】
【再次查看StatefulElement】
让我们捋一下思路:
1. 无论是哪种Widget都会实现createElement方法;
2. createElement方法会返回各自的Element子类;
3. 各自的Element子类都会有一个build方法且返回类型是Widget;
4. StatelessElement实现build方法是通过widget.build(this);
5. StatefulElement实现build方法是通过state.build(this);
看到这里,我们隐约知道,Widget和Element存在着一定关系。再结合源码里的一段注释:
我们知道:Element是用来管理此小部件(Widget)在Widget树中的位置。
Widget、Element、Render三棵树的执行顺序
开启debug运行
进入断点后,点击进入下一步
进入mount
查看mount注释
所以我们知道:有新的Element被添加到树时,框架会调用mount函数。
前面的铺垫是为了找到mount的注释,我们知道RenderObjectWidget
才会创建三棵树。
RenderObjectWidget
类的【createElement】方法和【createRenderObject】方法是抽象方法
,所以我们来到它的子类MultiChildRenderObjectWidget
下断点:
在MultiChildRenderObjectWidget
没有实现【createRenderObject】方法,所以来到它的子类Flex
下断点:
开启debug调试(这里以Column
为例子),如果发现不是我们要探究的就下一步:
找到了Column
真正调用【createElement】
继续放过断点,发现进入了方法Column
的【createRenderObject】
点击RenderObjectElement.mount (framework.dart:5459)
这一行
我们前面分析过,当Element被创建并添加到树时,会调用mount方法
,而上图【mount】方法里调用了一句代码:
_renderObject = widget.createRenderObject(this);
所以由此可见,【createRenderObject】是在【createElement】之后才被调用的;
结论:
-
Element和mount方法一一对应
-
三棵树的创建先后顺序:
Widget树
->Element树
->Render树
1、调用Widget构造函数
2、Widget会调用【createElement】创建Element树,紧接着调用mount方法;
3、如果Widget继承自RenderObjectWidget,mount方法内部会调用【createRenderObject】创建Render树;
4、如果Widget不是继承自RenderObjectWidget,mount方法内部就不会调用【createRenderObject】
// 即:只有继承自RenderObjectElement的Element,才会去创建Render。
三棵树具体是干啥的?
了解了三棵树的创建顺序,但是我们不禁发声:这些树创建有啥用?
目前我们只知道,Element树的mount决定着要不要创建Render树。
StatelessWidget的build方法的调用过程
进入StatelessWidget
进入StatelessElement
进入ComponentElement
进入rebuild
选中performRebuild,然后按住快捷键组合:command
+ option
+ B
选择(ComponentElement那个)进入
进入build,快捷键组合:command
+ option
+ B
选择(StatelessElement那个)进入
debug跑了下
可以看出来,StatelessElement的build调用,实际上是调用自定义StatelessWidget(比如MyApp)的build方法,也就是这个方法
捋一下思路:
1、调用StatelessWidget构造函数
2、调用createElement方法
3、调用ComponentElement类的mount方法
4、mount方法调用_firstBuild方法,也就是调用rebuild方法
5、rebuild方法调用ComponentElement类的performRebuild方法
6、performRebuild方法内部调用build()方法,build()方法在子类(StatelessElement)实现
7、StatelessElement类的build()方法在自定义StatelessWidget类实现(例如MyApp),参数this是StatelessElement
// 【StatelessElement】继承自【ComponentElement】
// 即:StatelessWidget构造函数 -> createElement -> Element调用build(Element)
StatefulWidget的build方法的调用过程
进入StatefulWidget
进入StatefulElement
// 去掉了assert断言,代码省略部分用...
class StatefulElement extends ComponentElement {
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
state._element = this;
state._widget = widget;//标记1
}
@override
Widget build() => state.build(this);
...
}
【标记1】这行代码说明,state保存了StatefulWidget对象,所以在我们平时写代码的时候,可以在State
类里通过【widget】去访问StatefulWidget里定义的成员变量
。比如:
发现相比StatefulWidget,这里多了一步创建_state
_state = widget.createState()
而调用build方法,中间部分跟StatelessWidget差不多,最后还是会通过state.build(this)
去调用(this指的是StatefulElement)。
总结:
1、调用StatefulWidget构造函数
2、调用createElement方法,内部创建_state对象,_state对象保存了当前StatefulWidget对象
3、调用ComponentElement类的mount方法
4、mount方法调用_firstBuild方法,也就是调用rebuild方法
5、rebuild方法调用ComponentElement类的performRebuild方法
6、performRebuild方法内部调用build()方法,build()方法在子类(StatefulElement)实现
7、StatefulElement类的build()方法在自定义的State类实现(例如_MineAPPState),参数this是StatefulElement
// 【StatefulElement】继承自【ComponentElement】
// 即:StatefulWidget构造函数 -> createElement -> _state调用build(Element)