「这是我参加2022首次更文挑战的第2天,活动概况检查:2022首次更文挑战」
在Flutter
烘托进程中有三棵树:Widget树
、Render树
和Element树
;
Widget树
什么是Widget树
呢,其实在咱们的Android Studio
中能够直观的看到某一个页面烘托之后Widget树
的样子,咱们以聊天界面为例看一下页面的Widget树
;
点击Android Studio
右侧的Flutter Inspector
工具,就能够呈现出当前页面的Widget树
的层级联系:
需求留意的是,Flutter
的烘托引擎并不是来直接烘托Widget树
的,因为假如直接烘托Widget树
,那么一旦build
办法履行,那么整个Widget
都需求重新烘托将会是非常消耗性能的(Widget
是经常发生变化的);
Render树
除了Widget树
,还有一个Render树
,其实**Flutter**
引擎烘托的是**RenderObject树**
,它里面是一个个的RenderObject
的目标;并非一切的Widget
都会生成RenderObject
,比方Container
;只有最终承继自RenderObjectWidget
的才会生成RenderObject
,比方Column
;
在RenderObjectWidget
中有几个需求咱们留意的当地,咱们来看一下RenderObjectWidget
的源码:
abstract class RenderObjectWidget extends Widget {
const RenderObjectWidget({ Key? key }) : super(key: key);
@override
@factory
RenderObjectElement createElement();
@protected
@factory
RenderObject createRenderObject(BuildContext context);
@protected
void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }
@protected
void didUnmountRenderObject(covariant RenderObject renderObject) { }
}
在RenderObjectWidget
中有createElement()
和createRenderObject()
两个笼统办法;这两个办法需求RenderObjectWidget
的子类来完成,咱们能够经过Stack
的承继联系来检查发现RenderObjectWidget
的子类:
- 子类
MultiChildRenderObjectWidget
中完成了createElement
办法:
@override
MultiChildRenderObjectElement createElement() => MultiChildRenderObjectElement(this);
而MultiChildRenderObjectElement
承继自RenderObjectElement
;
- 子类
Stack
中完成了createRenderObject
办法:
@override
RenderStack createRenderObject(BuildContext context) {
assert(_debugCheckHasDirectionality(context));
return RenderStack(
alignment: alignment,
textDirection: textDirection ?? Directionality.maybeOf(context),
fit: fit,
clipBehavior: overflow == Overflow.visible ? Clip.none : clipBehavior,
);
}
在这个办法中创立了一个RenderStack
,而根据RenderStack
的承继链发现其承继自RenderObject
;
综上,承继自RenderObjectWidget
的目标,既会创立Element树
,又会创立RenderObject树
;
Element树
咱们根据承继链能够发现StatelessWidget
直接承继自Widget
,其内部没有RenderObject
目标,但是有Element
目标:
在Widget
的源码中存在createElement()
的笼统办法,也便是一切承继自Widget
的目标都有Element
目标:Widget树
和Element树
是一一对应的联系;
同样的,在StatefulWidget
中完成了相同的办法:
咱们在StatefulWidget
中的createElement
办法打上断点,然后运用Debug
模式运转项目,检查一下断点的情况:
咱们发现,从整个项目运转开始,第一个调用createElement
的是MaterialApp
这个组件;此刻的this
便是MaterialApp
;
那么假如,咱们将断点打在StatelessWidget
中,咱们来看一下履行的情况:
此刻的this
将会指向MyApp
;咱们的main.dart
文件如下:
这个时分,咱们单步履行一下:
这个时分代码将会履行到:
此处接下来将会履行mount
办法,咱们来看一下mount
办法,咱们首要看一下注释:
从注释咱们能够得知,当有一个新的Element
被添加到Element树
的时分,mount
办法将会被调用;因为Widget
与Element
是一一对应的,所以咱们也能够理解为当有一个Widget
被创立的时分,mount
办法就会被调用;
新添加的
Element
与原来的旧Element
是有差异的;
咱们从上文已经知道StatefulWidget
和StatelessWidget
是没有RenderObject
目标的,那么咱们持续检查一下有RenderObject
目标的组件的mount
办法:
单步断点履行:
接下来断点进入mount
办法:
咱们发现此刻的mount
办法调用了super.mount
,咱们进入super.mount
办法:
咱们发现在super.mount
办法中调用了creatRenderObject
办法,此刻的mount
办法是由RenderObjectElement
完成的;
那么咱们能够得出一下定论:
在
Flutter
烘托流程中,最终是针对Render树
中的目标进行烘托;当一个Widget
被创立时,都会经过createElement
办法创立一个Element
加入到Element树
中,然后会履行mount
办法,此刻假如含有RenderObject
(Element
是否承继自RenderObjectElement
),则会在mount
办法中经过createRenderObject
办法创立RenderObject树
,反之则不创立;