Some time ago, I had a brief introduction to xiao CAIWidgetOf whichWidget 是 immutableImmutable, whileWidgetIs how to achieve the update redraw, this cannot leaveElement 和 RenderObject; A brief introduction to the side dishesElementRelevant knowledge;

Element

      Element 是 Widget 在 UIAn instantiated object at a specific location in the tree;UI View 在 ElementA real one is built into the hierarchyElement TreeIs the true view tree structure;ElementAs aWidget 和 RenderObjectBetween coordinators and underWidgetTo complete the operation of adding, deleting and changing nodes;

Source code analysis

Element involves a long source code, xiao CAI only for specific methods and life cycle for learning;

The life cycle

enum _ElementLifecycle {
  initial,
  active,
  inactive,
  defunct,
}
Copy the code

The life cycle of an Element consists of initial, active, inactive and defunct.

In view of the way

1. createElement
Element(Widget widget) : assert(widget ! = null), _widget = widget;Copy the code

Create an Element that uses the specified Widget as its configuration. Create an Element by calling Widget.createElement from the Widget as its initial location;

2. mount
@mustCallSuper void mount(Element parent, dynamic newSlot) { ... _parent = parent; _slot = newSlot; _depth = _parent ! = null ? _parent.depth + 1 : 1; _active = true; if (parent ! = null) _owner = parent.owner; if (widget.key is GlobalKey) { final GlobalKey key = widget.key; key._register(this); } _updateInheritance(); }Copy the code

Mount () adds the newly created Element to the specified parent slot tree by calling attachRenderObject.

3. update
@protected Element updateChild(Element child, Widget newWidget, dynamic newSlot) { if (newWidget == null) { if (child ! = null) deactivateChild(child); return null; } if (child ! = null) { if (child.widget == newWidget) { if (child.slot ! = newSlot) updateSlotForChild(child, newSlot); return child; } if (Widget.canUpdate(child.widget, newWidget)) { if (child.slot ! = newSlot) updateSlotForChild(child, newSlot); child.update(newWidget); return child; } deactivateChild(child); assert(child._parent == null); } return inflateWidget(newWidget, newSlot); }Copy the code

UpdateChild is Element’s core method, called whenever a child needs to be added, modified, or deleted. It is used to update elements based on Widget changes and then update the UI tree.

newWidget == null newWidget ! = null
child == null Returns null. Returns new [Element].
child ! = null Old child is removed, returns null. Old child updated if possible, returns child or new [Element].
  1. If the updated Widget is null, the child node is removed. If the child is not null, the child node is removed.
  2. If the updated Widget is not null and the current child is null, the new Widget is newly created and the inflateWidget creates child nodes.
  3. If the updated Widget is not null and the current child is not null and the node exists, child. Widget == newWidget indicates that the child node has not changed, and child.slot! = newSlot Indicates that the child node is moved between siblings, and updateSlotForChild updates the node position. Otherwise, return the child node directly;
  4. When the updated Widget is not null and the current child is not null, the widget. canUpdate is true, which means that the child node can be modified with the newWidget. Otherwise, remove the child node and create a new child node using newWidget; CanUpdate determines whether the key and runtimeType of the new and old widgets are the same.
4. deactivate
@protected
void deactivateChild(Element child) {
    child._parent = null;
    child.detachRenderObject();
    owner._inactiveElements.add(child); // this eventually calls child.deactivate()
}
Copy the code

DeactivateChild specifies that the Element is in the inactive Element list and removes the render object from the render tree; This method prevents Element from becoming a subclass;

5. activate
@mustCallSuper void activate() { final bool hadDependencies = (_dependencies ! = null && _dependencies.isNotEmpty) || _hadUnsatisfiedDependencies; _active = true; _dependencies? .clear(); _hadUnsatisfiedDependencies = false; _updateInheritance(); if (_dirty) owner.scheduleBuildFor(this); if (hadDependencies) didChangeDependencies(); }Copy the code

Activate () When an Element is rejoined to the tree, the frame removes the Element from the inactive inactive Element list, and the Element calls Activate and adds the Element’s render object to the tree;

6. unmount
@mustCallSuper void unmount() { if (widget.key is GlobalKey) { final GlobalKey key = widget.key; key._unregister(this); }}Copy the code

Unmount () is called when the frame will never be reactivated; In order to avoid repeated creation during the animation execution, when removing a specific Element, the inactive Element will be retained in the last frame of the current animation process. If it has not become active by the end of the animation, unmount() will be called to remove the Element completely.

Corresponding relations between

  1. Widget.createElement is the initial initialization lifecycle from scratch;
  2. Mount indicates the transition from initial to Active.
  3. Update is called only when active is active;
  4. Deactivate Transitions the life cycle from active to inactive.
  5. Activate Indicates the lifecycle transition from inactive inactive state to Active state.
  6. Unmount is the transition from inactive inactive state to defunct inactive state;

Subclasses Element

Element has two subclasses: ComponentElement and RenderObjectElement.

ComponentElement

ComponentElement (StatelessElement/StatefulElement/ProxyElement); Each Element corresponds to the Widget;

StatelessElement
class StatelessElement extends ComponentElement { StatelessElement(StatelessWidget widget) : super(widget); @override StatelessWidget get widget => super.widget; @override Widget build() => widget.build(this); @override void update(StatelessWidget newWidget) { super.update(newWidget); assert(widget == newWidget); _dirty = true; rebuild(); }}Copy the code

StatelessElement is relatively simple, mainly rewrite update() to rebuild() when needed;

StatefulElement
@override
void update(StatefulWidget newWidget) {
    super.update(newWidget);
    final StatefulWidget oldWidget = _state._widget;
    _dirty = true;
    _state._widget = widget;
    try {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      final dynamic debugCheckForReturnedFuture = _state.didUpdateWidget(oldWidget) as dynamic;
    } finally {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
    }
    rebuild();
}
Copy the code

The StatefulElement corresponds to the StatefulWidget and includes the full Element lifecycle, with State and rebuild() updated when updated;

ProxyElement
abstract class ProxyElement extends ComponentElement ProxyElement(ProxyWidget widget) : super(widget); @override ProxyWidget get widget => super.widget; @override Widget build() => widget.child; @override void update(ProxyWidget newWidget) { final ProxyWidget oldWidget = widget; assert(widget ! = null); assert(widget ! = newWidget); super.update(newWidget); assert(widget == newWidget); updated(oldWidget); _dirty = true; rebuild(); } @protected void updated(covariant ProxyWidget oldWidget) { notifyClients(oldWidget); } @protected void notifyClients(covariant ProxyWidget oldWidget); }Copy the code

ProxyElement is an abstract class that subclasses ParentDataElement and InheritedElement; Update () is called when the Widget is updated; NotifyClients () is called when the old and new widgets have indeed changed;

RenderObjectElement

RenderObjectElement Element corresponds to RenderObjectWidget; RenderObjectElement as an abstract class also inherits all of Element’s lifecycle methods;

Most of the RenderObjectElement only corresponds to a RenderObject is only a child node, such as RootRenderObjectElement/SingleChildRenderObjectElement; But there are also special, such as LeafRenderObjectElement subclass no child nodes, and section MultiChildRenderObjectElement subclasses can have more children;


Element acts as a mediator between Widget and RenderObject; The side dish pair will learn briefly about RenderObject in the next article; Xiao CAI’s understanding of the source code is not deep enough, if there are mistakes, please guide!

Source: Little Monk A Ce