likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 48

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树,反之则不创建;

转载自:https://juejin.cn/post/7054711662619656205
评论
请登录