Painted levels: being fostered fostered fostered

Tags: “Flutter” “Element” “Important method and call timing


In the last article we briefly introduced what Element is in Flutter and its life cycle. In this article, we’ll take a look at some of Element’s important methods and when to call them.

An important approach to Element

  • void mount(Element parent, dynamic newSlot)

** Adds the current element to the given slot in the parent Element. When a newly created element is added to the tree for the first time,

  • Element updateChild(Element child, Widget newWidget, dynamic newSlot)

** Description: ** Updates the element in the tree with the new configuration widget. This approach is at the heart of the Widges system.

** Each time a child element is added, updated, or removed from the tree based on the updated widget.

Method principle:

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].
“`dart
Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
if (newWidget == null) {
if (child ! //newWidget== null Discard Element deactivateChild(child); return null;Copy the code

} Element newChild; if (child ! = null) {/// flag bit: solve the type error caused by the different types of hot reload widgets. StatelessWidget(StatelessElement); StatelessWidget(StatelessElement); bool hasSameSuperclass = true; assert(() { ///element is StatefulElement ? 1 : element is StatelessElement ? 2:0; final int oldElementClass = Element._debugConcreteSubtype(child); /// widget is StatefulWidget ? 1 : widget is StatelessWidget ? 2:0; final int newWidgetClass = Widget._debugConcreteSubtype(newWidget); HasSameSuperclass = oldElementClass == newWidgetClass; hasSameSuperclass = oldElementClass == newWidgetClass; return true; } ()); HasSameSuperclass && child.widget == newWidget) {/// The element has only one child and its slot is null if (child.slot! = newSlot) /// Effect: modify the slot occupied by the given child in its parent. / / / call the timing: MultiChildRenderObjectElement / / / and other have multiple object rendering RenderObjectElement subclass. /// when their child moves from one location in Element’s Child (renderObject) array /// to another location. updateSlotForChild(child, newSlot); newChild = child; } else if (hasSameSuperclass && Widget.canupdate (child.widget, newWidget)) {/// ask widget.canupdate if (child.slot! = newSlot) /// Change the slot occupied by the given child in its parent. updateSlotForChild(child, newSlot); // update the current child Element child.update(newWidget) with the new configuration; assert(child.widget == newWidget); assert(() { child.owner._debugElementWasRebuilt(child); return true; } ()); newChild = child; } else {/// Discard the current child Element deactivateChild(child); assert(child._parent == null); NewChild = inflateWidget(newWidget, newSlot); }} else {///child == null Create new newChild = inflateWidget(newWidget, newSlot); }

assert(() { if (child ! = null) _debugRemoveGlobalKeyReservation(child); final Key key = newWidget? .key; if (key is GlobalKey) { key._debugReserveFor(this, newChild); } return true; } ());

return newChild;

}

- 'void update(covariant Widget newWidget)' ** Description: ** Modifies the 'Widget' used to configure this' element 'with the new' Widget '. ** When the parent Element wants to update the element with a different widget, the new widget must have the same runtimeType as the old widget. - 'Element inflateWidget(Widget newWidget, dynamic newSlot)' ** ** Creates an element for the given 'widget' and adds it as a child to the given 'element' slot of the current 'element'. ** This method is usually called by 'updateChild', but can also be called directly by subclasses that need more fine-grained control over the 'element' they create. * * note: ** If the given 'widget' has a 'global key' and its corresponding 'Element' already exists, this function will reuse the 'Element' (possibly porting it from another location in the tree, or reactivating it from the inactive element list) instead of creating a new element. The 'element' returned by this method is already 'mounted' and in the 'active' state. ```dart Element inflateWidget(Widget newWidget, dynamic newSlot) { assert(newWidget ! = null); final Key key = newWidget.key; If (key is GlobalKey) {/// Retrieve it from the inactive list. ///1.final Element element = key._currentElement; //2. Element == null or! Widget.canUpdate(element.widget, newWidget) ///reture null ///3. final Element parent = element._parent; ///4. parent.forgetChild(element); ///5. parent.deactivateChild(element); ///6.owner._inactiveElements.remove(element); ///7.return element final Element newChild = _retakeInactiveElement(key, newWidget); if (newChild ! = null) { assert(newChild._parent == null); assert(() { _debugCheckForCycles(newChild); return true; } ()); /// reactivate the acquired 'element'. / / / 1. Modify the ` parent ` / / / 2. _updateDepth (int parentDepth) / / / 3. Recursive traversal modifies the state of all child elements in 'element' not 'active'. /// For 'element' with 'children'. Call attachRenderObject(dynamic newSlot) /// Add render object to tree. newChild._activateWithParent(this, newSlot); // update this element with a new 'widget', final Element updatedChild = updateChild(newChild, newWidget, newSlot) on the new 'slot'; assert(newChild == updatedChild); // return updatedChild; Final Element newChild = newWidget.createElement(); final Element newChild = newWidget.createElement(); assert(() { _debugCheckForCycles(newChild); return true; } ()); /// Mount: Add to the tree. newChild.mount(this, newSlot); assert(newChild._debugLifecycleState == _ElementLifecycle.active); return newChild; }Copy the code
  • void deactivateChild(Element child)

** Description: ** Removes the given element from the Inactive Elements list and separates the corresponding Render object from the render tree.

** Call timing: ** Normally called when an element updates (deletes) its child element, but when the global Key changes the parent node, the new parent actively calls the old parent’s deactivateChild and first calls the old parent’s forgetChild to update the old parent.

 void deactivateChild(Element child) {
    assert(child ! =null);
    assert(child._parent == this);
    ///Go to the father
    child._parent = null;
    ///Separate its render object
    child.detachRenderObject();
    ///Add to an inactive array
    owner._inactiveElements.add(child); // this eventually calls child.deactivate()
    assert(() {
      if (debugPrintGlobalKeyedWidgetLifecycle) {
        if (child.widget.key is GlobalKey)
          debugPrint('Deactivated $child (keyed child of $this) ');
      }
      return true; } ()); }Copy the code
  • void detachRenderObject()

** Description: ** Removes a render object from the render tree.

** Call timing: ** is normally called in the deactivateChild method

Note: * * * * the function of the default implementation just for their child recursive call detachRenderObject, but RenderObjectElement. After detachRenderObject rewrite this method, on the cover (not call super).

  void detachRenderObject() {
    visitChildren((Element child) {
      child.detachRenderObject();
    });
    _slot = null;
  }
Copy the code
  • void forgetChild(Element child)

** Description: ** Removes the given child from the element’s child list in preparation for reuse elsewhere in the element tree.

** Call timing: ** Usually before the deactivateChild method is called. Update is responsible for creating or updating a new child to replace the child. About the detailed usage of this method can check MultiChildRenderObjectElement class, such forgetChild affects the update for replaceWithNullIfForgotten method calls, It also affects the traversal of child elements by visitChildren.

  • void updateSlotForChild(Element child, dynamic newSlot)

** Modifies the slot the given child occupies in the parent element. With more than one call timing: MultiChildRenderObjectElement and other rendering object RenderObjectElement subclass. When their child moves from one location in Element’s Child (renderObject) array to another location.

 void updateSlotForChild(Element child, dynamic newSlot) {
    assert(_debugLifecycleState == _ElementLifecycle.active);
    assert(child ! =null);
    assert(child._parent == this);
    void visit(Element element) {
      element._updateSlot(newSlot);
      if (element is! RenderObjectElement)
        element.visitChildren(visit);
    }
    visit(child);
  }
Copy the code
  • void activate()

** Changes the life cycle of an element from Inactive to active. ** Call timing: ** The framework calls this method when a previously disabled element is remerged into the tree. When the element is first activated (that is, when the state starts with Initial), the framework does not call this method, but by calling mount.

void activate() {
    ....
    final boolhadDependencies = (_dependencies ! =null && _dependencies.isNotEmpty) || _hadUnsatisfiedDependencies;
    _active = true;
    // We unregistered our dependencies in deactivate, but never cleared the list.
    // Since we're going to be reused, let's clear our list now._dependencies? .clear(); _hadUnsatisfiedDependencies =false;
    _updateInheritance();
    assert(() {
      _debugLifecycleState = _ElementLifecycle.active;
      return true; } ());if (_dirty)
      ///Adds the element to`dirty element`In the list,
      ///In order to`WidgetsBinding.drawFrame`call`buildScope`
     ///It will be rebuilt.
      owner.scheduleBuildFor(this);
    if (hadDependencies)
      didChangeDependencies();
  }
Copy the code
  • void attachRenderObject(dynamic newSlot)

** Add the renderObject to the location specified by slot in the render tree. Call time: * * * * the function of the default implementation just for its child recursive call attachRenderObject, but RenderObjectElement. After attachRenderObject rewrite this method, on the cover (not call super).

 void attachRenderObject(dynamic newSlot) {
    assert(_slot == null);
    visitChildren((Element child) {
      child.attachRenderObject(newSlot);
    });
    _slot = newSlot;
  }
Copy the code
  • void unmount()

Description: Life cycle changes from Inactive to defunct. ** Call timing: ** Called when the framework determines that an element in inactive state will never be activated. At the end of each animation, the framework unmounts any element that remains inactive to prevent an inactive element from remaining inactive longer than a single animation frame. After this function is called, the element will no longer be merged into the tree.

  • void reassemble()

Description: A debugging strategy for rapid development. Call timing: When the application is reassembled during debugging, for example, during Hot Reload. This function is called only during development, and if reAssemble is called, build will be called at least once.

  • void didChangeDependencies()

Call timing: Called when the dependency of this element changes. Such as This element dependent InheritedElement. Update new InheritedWidget and InheritedWidget updateShouldNotify returns true, the framework will invoke this method, notice this element to make corresponding changes.

  • void markNeedsBuild()

Description: Mark the element as dirty and add it to the global widget list for reconstruction in the next frame. Call time: setState, ReAssemble, didChangeDependencies.

  • void rebuild()

Call timing:

  1. whenBuildOwner.scheduleBuildForThis element has been marked asdirtyWhen theBuildOwnerCall;
  2. When the element goes throughmountCalled when it is first built;
  3. When the elementwidgetthroughupdateThis method is called when it has been changed.

Ways to focus on us are:

QiShare(GitHub) QiShare(CocoaChina) QiShare(StackOverflow) QiShare(wechat)

Element in Flutter

B Swift 5.1 (21) – Generic Swift 5.1 (20) – Protocol Swift 5.1 (19) – Extension Swift 5.1 (18) – Nested types Swift 5.1 (17) – Type conversion and pattern matching