前言
讲到Flutter的渲染原理,就离不开Flutter中的三棵树(Widget Tree
、Element Tree
、Render Tree
)。
当应用启动时 Flutter 会遍历并创建所有的 Widget 形成 Widget Tree
,同时与 Widget Tree
相对应,通过调用 Widget 上的 createElement()
方法创建每个 Element 对象,形成 Element Tree
。
如果是继承自RenderObjectWidget
的Widget,最后调用 Element 的 createRenderObject()
方法创建每个渲染对象,形成一个 Render Tree
。
并不是所有的Widget都会被独立渲染,只有继承RenderObjectWidget
的才会创建RenderObject
对象!也就组成了Render Tree
!
Widget
正如 Flutter 的口号 Everything’s a widget,万物皆Widget。一个Flutter应用能正常运行,展示出来的UI就是由一个个Widget搭建构成的。
@immutable
abstract class Widget extends DiagnosticableTree {
/// Initializes [key] for subclasses.
const Widget({ this.key });
final Key? key;
@protected
@factory
Element createElement();
/// Whether the `newWidget` can be used to update an [Element] that currently
/// has the `oldWidget` as its configuration.
///
/// An element that uses a given widget as its configuration can be updated to
/// use another widget as its configuration if, and only if, the two widgets
/// have [runtimeType] and [key] properties that are [operator==].
///
/// If the widgets have no key (their key is null), then they are considered a
/// match if they have the same type, even if their children are completely
/// different.
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
Widget 的 canUpdate
方法通过比较新部件和旧部件的 runtimeType
和 key
属性是否相同来决定更新部件对应的 Element。
Element
Element 更像是一个Widget的实例化对象
,Widget 调用createElement
方法生成一对一关系的Element,Widget根据canUpdate
方法来判断是否创建新的Element来替代旧的Element,这也是Flutter渲染效率高的原因所在,Element的复用。
abstract class Element extends DiagnosticableTree implements BuildContext {
/// Creates an element that uses the given widget as its configuration.
///
/// Typically called by an override of [Widget.createElement].
Element(Widget widget)
: assert(widget != null),
_widget = widget;
/// The configuration for this element.
@override
Widget get widget => _widget!;
Widget? _widget;
@mustCallSuper
void mount(Element? parent, Object? newSlot){...}
@mustCallSuper
void update(covariant Widget newWidget) {
// This code is hot when hot reloading, so we try to
// only call _AssertionError._evaluateAssertion once.
assert(
_lifecycleState == _ElementLifecycle.active
&& widget != null
&& newWidget != null
&& newWidget != widget
&& depth != null
&& Widget.canUpdate(widget, newWidget),
);
// This Element was told to update and we can now release all the global key
// reservations of forgotten children. We cannot do this earlier because the
// forgotten children still represent global key duplications if the element
// never updates (the forgotten children are not removed from the tree
// until the call to update happens)
assert(() {
_debugForgottenChildrenWithGlobalKey.forEach(_debugRemoveGlobalKeyReservation);
_debugForgottenChildrenWithGlobalKey.clear();
return true;
}());
_widget = newWidget;
}
RenderObject
RenderObject 用于应用界面的布局和绘制,保存了元素的大小,布局等信息,实例化一个 RenderObject 是非常耗能的。
abstract class RenderObjectWidget extends Widget {
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const RenderObjectWidget({ Key? key }) : super(key: key);
/// RenderObjectWidgets always inflate to a [RenderObjectElement] subclass.
@override
@factory
RenderObjectElement createElement();
/// Creates an instance of the [RenderObject] class that this
/// [RenderObjectWidget] represents, using the configuration described by this
/// [RenderObjectWidget].
///
/// This method should not do anything with the children of the render object.
/// That should instead be handled by the method that overrides
/// [RenderObjectElement.mount] in the object rendered by this object's
/// [createElement] method. See, for example,
/// [SingleChildRenderObjectElement.mount].
@protected
@factory
RenderObject createRenderObject(BuildContext context);
}
如前文所说,只有继承自RenderObjectWidget
的Widget对象并实现了createRenderObject
方法创建一个RenderObject
对象的Widget对象,才能成为Render Tree
的一个组成部分。
解析Widget、Element、Render 关系
查看StatelessWidget源码:
abstract class StatelessWidget extends Widget {
/// Initializes [key] for subclasses.
const StatelessWidget({ Key? key }) : super(key: key);
/// Creates a [StatelessElement] to manage this widget's location in the tree.
///
/// It is uncommon for subclasses to override this method.
@override
StatelessElement createElement() => StatelessElement(this);
considerations.
@protected
Widget build(BuildContext context);
}
如前文所说,Widget 和 Element的一对一关系,StatelessWidget实现了createElement方法,将自身Widget作为参数,并返回了一个StatelessElement对象。
对比StatefulWidget源码:
abstract class StatefulWidget extends Widget {
/// Initializes [key] for subclasses.
const StatefulWidget({ Key? key }) : super(key: key);
/// Creates a [StatefulElement] to manage this widget's location in the tree.
///
/// It is uncommon for subclasses to override this method.
@override
StatefulElement createElement() => StatefulElement(this);
@protected
@factory
State createState(); // ignore: no_logic_in_create_state, this is the original sin
}
我们可以分别在两个对象的createElement
方法处打个断点,调试环境查看代码如何运行及第一个来的是哪个对象。
第一个StatefullWidget
断点调试,StatelessWidget和StatefullWidget 都会调用createElement
方法,不同的是返回对象不同,一个是StatelessElement
,一个是StatefulElement
。但都是继承自ComponentElement
,查看源码:
class StatelessElement extends ComponentElement {
/// Creates an element that uses the given widget as its configuration.
StatelessElement(StatelessWidget widget) : super(widget);
@override
StatelessWidget get widget => super.widget as StatelessWidget;
@override
Widget build() => widget.build(this);
@override
void update(StatelessWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
_dirty = true;
rebuild();
}
}
class StatefulElement extends ComponentElement {
/// Creates an element that uses the given widget as its configuration.
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
assert(() {
if (!state._debugTypesAreRight(widget)) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('StatefulWidget.createState must return a subtype of State<${widget.runtimeType}>'),
ErrorDescription(
'The createState function for ${widget.runtimeType} returned a state '
'of type ${state.runtimeType}, which is not a subtype of '
'State<${widget.runtimeType}>, violating the contract for createState.',
),
]);
}
return true;
}());
assert(state._element == null);
state._element = this;
assert(
state._widget == null,
'The createState function for $widget returned an old or invalid state '
'instance: ${state._widget}, which is not null, violating the contract '
'for createState.',
);
state._widget = widget;
assert(state._debugLifecycleState == _StateLifecycle.created);
}
@override
Widget build() => state.build(this);
/// The [State] instance associated with this location in the tree.
///
/// There is a one-to-one relationship between [State] objects and the
/// [StatefulElement] objects that hold them. The [State] objects are created
/// by [StatefulElement] in [mount].
State<StatefulWidget> get state => _state!;
State<StatefulWidget>? _state;
}
继续调试模式,点击下一步⬇️,发现不管是StatelessWidget和StatefullWidget都会执行mount方法:
mount方法调用时机
我们来到ComponentElement的源码,看到mount方法:
abstract class ComponentElement extends Element {
/// Creates an element that uses the given widget as its configuration.
ComponentElement(Widget widget) : super(widget);
Element? _child;
bool _debugDoingBuild = false;
@override
bool get debugDoingBuild => _debugDoingBuild;
@override
void mount(Element? parent, Object? newSlot) {
super.mount(parent, newSlot);
assert(_child == null);
assert(_lifecycleState == _ElementLifecycle.active);
_firstBuild();
assert(_child != null);
}
void _firstBuild() {
rebuild();
}
@override
@pragma('vm:notify-debugger-on-exception')
void performRebuild() {...}
}
按照mount -> _firstBuild -> rebuild -> performRebuild,option + command + b , 选择 ComponentElement ,看到built = build(); 最终来到StatelessElement 及 StatefulElement 中的build方法。然后对StatelessElement 和 StatefulElement 中的build 进行分析,发现遛了一大圈,终于到了build方法。
结论
- StatelessElement 继承ComponentElement
- 将自己(widget)传给父类ComponentElement
- 调用build方法并将自己(Element)传回去,所以build(BuildContext context)方法里的context就是Element。
- StatefulElement 继承ComponentElement
- 调用createState方法,创建state
- 将element赋值给state,所以widget和state的element是同一个
- 将widget赋值给state,所以在state里面可以通过widget点方法来获取到Widget中的数据
- 调用state的build方法并将自己(Element)传出去
RenderObjectWidget的创建
自定义一个Row或者Column,查看源码,最终来到RenderObjectElement的源码:
abstract class RenderObjectElement extends Element {
/// Creates an element that uses the given widget as its configuration.
RenderObjectElement(RenderObjectWidget widget) : super(widget);
@override
RenderObjectWidget get widget => super.widget as RenderObjectWidget;
@override
void mount(Element? parent, Object? newSlot) {
super.mount(parent, newSlot);
assert(() {
_debugDoingBuild = true;
return true;
}());
_renderObject = widget.createRenderObject(this);
assert(!_renderObject!.debugDisposed!);
assert(() {
_debugDoingBuild = false;
return true;
}());
assert(() {
_debugUpdateRenderObjectOwner();
return true;
}());
assert(_slot == newSlot);
attachRenderObject(newSlot);
_dirty = false;
}
}
由此可见,继承自RenderObjectElement的Element最终会通过mount
方法来调用createRenderObject
方法,创建自己的render
对象。
结论
RenderElement主要是创建RenderObject对象
- 继承RenderObjectWidget的Widget会创建RenderElement
- 创建RanderElement
- Flutter会调用mount方法,调用createRanderObject方法
网友评论