「这是我参加2022首次更文挑战的第2天,活动概况检查:2022首次更文挑战」

Flutter烘托进程中有三棵树:Widget树Render树Element树

Widget树

什么是Widget树呢,其实在咱们的Android Studio中能够直观的看到某一个页面烘托之后Widget树的样子,咱们以聊天界面为例看一下页面的Widget树

点击Android Studio右侧的Flutter Inspector工具,就能够呈现出当前页面的Widget树的层级联系:

Flutter(三十四)-Widget树、Render树和Element树

需求留意的是,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目标:

Flutter(三十四)-Widget树、Render树和Element树

Widget的源码中存在createElement()的笼统办法,也便是一切承继自Widget的目标都有Element目标:Widget树Element树是一一对应的联系;

同样的,在StatefulWidget中完成了相同的办法:

Flutter(三十四)-Widget树、Render树和Element树

咱们在StatefulWidget中的createElement办法打上断点,然后运用Debug模式运转项目,检查一下断点的情况:

Flutter(三十四)-Widget树、Render树和Element树

咱们发现,从整个项目运转开始,第一个调用createElement的是MaterialApp这个组件;此刻的this便是MaterialApp

那么假如,咱们将断点打在StatelessWidget中,咱们来看一下履行的情况:

Flutter(三十四)-Widget树、Render树和Element树

此刻的this将会指向MyApp;咱们的main.dart文件如下:

Flutter(三十四)-Widget树、Render树和Element树

这个时分,咱们单步履行一下:

Flutter(三十四)-Widget树、Render树和Element树

这个时分代码将会履行到:

Flutter(三十四)-Widget树、Render树和Element树

此处接下来将会履行mount办法,咱们来看一下mount办法,咱们首要看一下注释:

Flutter(三十四)-Widget树、Render树和Element树

从注释咱们能够得知,当有一个新的Element被添加到Element树的时分,mount办法将会被调用;因为WidgetElement是一一对应的,所以咱们也能够理解为当有一个Widget被创立的时分,mount办法就会被调用;

新添加的Element与原来的旧Element是有差异的;

咱们从上文已经知道StatefulWidgetStatelessWidget是没有RenderObject目标的,那么咱们持续检查一下有RenderObject目标的组件的mount办法:

Flutter(三十四)-Widget树、Render树和Element树

单步断点履行:

Flutter(三十四)-Widget树、Render树和Element树

接下来断点进入mount办法:

Flutter(三十四)-Widget树、Render树和Element树

咱们发现此刻的mount办法调用了super.mount,咱们进入super.mount办法:

Flutter(三十四)-Widget树、Render树和Element树

咱们发现在super.mount办法中调用了creatRenderObject办法,此刻的mount办法是由RenderObjectElement完成的;

那么咱们能够得出一下定论:

Flutter烘托流程中,最终是针对Render树中的目标进行烘托;当一个Widget被创立时,都会经过createElement办法创立一个Element加入到Element树中,然后会履行mount办法,此刻假如含有RenderObject(Element是否承继自RenderObjectElement),则会在mount办法中经过createRenderObject办法创立RenderObject树,反之则不创立;