Flutter - 初探渲染原理

前言

讲到Flutter的渲染原理,就离不开Flutter中的三棵树(Widget TreeElement TreeRender 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 方法通过比较新部件和旧部件的 runtimeTypekey 属性是否相同来决定更新部件对应的 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方法处打个断点,调试环境查看代码如何运行及第一个来的是哪个对象。

第一个StatelessWidget

第一个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([
          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 get state => _state!;
  State? _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方法。

结论

  1. StatelessElement 继承ComponentElement
    • 将自己(widget)传给父类ComponentElement
    • 调用build方法并将自己(Element)传回去,所以build(BuildContext context)方法里的context就是Element。
  2. 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方法

你可能感兴趣的:(Flutter - 初探渲染原理)