Flutter 源码阅读 - 三棵树流程分析(一)
日常工作中我们所编写的一个个 Widget,它到底是什么东西、以及它是如何展现在用户面前的? 本系列文章将会通过一些小的案例以及源码来进行分析 Flutter 中 Widget、Element、RenderObject 三棵树之间的关系以及它们各自的作用(注意:本系列文章对 Layer 暂不做探讨)。
本篇文章将会通过源码先对他们做一个简单的分类,让读者先留下一个印象。在后续的文章中将会逐渐进行深入分析。
一、 Widget 的分类
Flutter 中是通过 Widget 嵌套来进行构建 UI 的(Flutter 中万物皆 Widget),我们首先来看下 Widget 的分类。

通过查看 Flutter 源码我们可以得出以上总结,Widget 大致可以分为 RenderObjectWidget 和组合型 Widget(根据有没有对应的 RenderObject来进行分类)。
RenderObjectWidget 又可以分为 LeafRenderObjectWidget、 SingleChildRenderObjectWidget、 MultiChildRenderObjectWidget 等。
通过下图源码我们可以看出 RenderObjectWidget 抽象类主要包含四个方法:createElement、createRenderObject、updateRenderObject、didUnmountRenderObject,其中 createElement 和 createRenderObject 为抽象方法,需要子类去实现。

RenderObjectWidgets provide the configuration for [RenderObjectElement]s, which wrap [RenderObject]s, which provide the actual rendering of the application.
通过注释我们可以看出 RenderObjectWidget 主要是为 RenderObjectElement提供配置,创建 RenderObject。
组合型 Widget 又可以分为 StatelessWidget、StatefulWidget、ProxyWidget等。这里我们主要主要看下 StatelessWidget 和 StatefulWidget。
StatelessWidget主要有 createElement 和 build 方法,其中 createElement 返回了一个 StatelessElement,build 则为抽象方法,就是我们经常实现的一个方法。
StatefulWidget 主要有 createElement 和 createState 方法,其中 其中 createElement 返回了一个 StatefulElement,createState也是一个抽象方法,也是我们我们经常实现的一个方法。通过 StatelessWidget 、 StatefulWidget 与 RenderObjectWidget 的源码进行对比我们发现主要是 RenderObjectWidget 多了 createRenderObject 抽象方法。那么 createElement 和 createRenderObject 主要是做什么的,又有哪些作用呢?在这里先留下一个疑问,后续将会进行讲解。

二、 Element 的分类

通过上面对 Widget 的了解,我们可以看出它主要就是为了创建 Element 而生的。相应的,每一个细分的 xxxWidget 都有对应的 xxxElement。
比如 StatelessWidget -> StatelessElement,StatefulWidget -> StatefulElement,InheritedWidget -> InheritedElement,LeafRenderObjectWidget -> LeafRenderObjectElement,SingleChildRenderObjectWidget -> SingleChildRenderObjectElement,MultiChildRenderObjectWidget -> MultiChildRenderObjectElement等。
每个 xxxElement 最终都会通过继承 ComponentElement 或 RenderObjectElement 来继承 Element 抽象类。这里与上面讲到的 Widget 相对应,组合型 Widget 对应 ComponentElenent,RenderObjectWidget 对应 RenderObjectElement。




通过 Element 抽象类的源码我们可以发现,Element 中持有 Widget、RenderObject。
// 简化后的 Element 源码
abstract class Element extends DiagnosticableTree implements BuildContext {
Element(Widget widget)
: assert(widget != null),
_widget = widget;
@override
Widget get widget => _widget!;
Widget? _widget;
RenderObject? get renderObject {
RenderObject? result;
void visit(Element element) {
assert(result == null);
if (element._lifecycleState == _ElementLifecycle.defunct) {
return;
} else if (element is RenderObjectElement) {
result = element.renderObject;
} else {
element.visitChildren(visit);
}
}
visit(this);
return result;
}
}
三、 RenderObject 的分类


通过源码中的注释可以看出 RenderObjectWithChildMixin 是为了渲染单子节点而生,ContainerRenderObjectMixin 是为了渲染多子节点而生,RelayoutWhenSystemFontsChangeMixin 是为了配合系统字体更改而生的。
四、最后
最后附上一张 Widget、Element、RenderObject 它们的全图,方便读者进行对比查看。

转载自:https://juejin.cn/post/7169495060097007630