「这是我参与11月更文挑战的第13天,活动概况检查:2021最终一次更文挑战」

昨日咱们讲了flutter三棵树(widget,element,renderObject),因为篇幅原因没有具体的酱element的生命周期,今日咱们再开看下element的生命周期

element生命周期

经过检查Element类咱们能够发现它是一个抽象类:

abstract class Element extends DiagnosticableTree implements BuildContext {
  Element(Widget widget)
    : assert(widget != null),
      _widget = widget;
  Element _parent;
  @override
  Widget get widget => _widget;
  Widget _widget;
  RenderObject get renderObject { ... }
  @mustCallSuper
  void mount(Element parent, dynamic newSlot) { ... }
  @mustCallSuper
  void activate() { ... }
  @mustCallSuper
  void deactivate() { ... }
  @mustCallSuper
  void unmount() { ... }

并包括以下四个生命周期办法

  1. mount
  2. activate
  3. deactivate
  4. unmount

创立Element

当widget调用createElement时会创立一个Element实例

mount

当调用element.mount时,mount办法首要调用createRenderObject创立renderObject而且调用attachRenderObject将之前创立的renderObject增加到renderTree上,这样element就处于active状况了,处于active状况就会显示到屏幕上

当widget进行更新时,为了防止从头创立element会相判别是否能够更新,会调用updateChild办法

  @protected
  Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
    if (newWidget == null) {
      if (child != null)
        deactivateChild(child);///没有新控件  而且有本来的控件,则移出本来的控件,
      return null;
    }
    Element newChild;
    if (child != null) {///本来有child
      if (hasSameSuperclass && child.widget == newWidget) {///相同的父控件类型,相同的子控件,直接更新child
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        newChild = child;
      } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
        ///相同的父控件类型,而且能够更新widget,则更新child
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        child.update(newWidget);
        assert(child.widget == newWidget);
        newChild = child;
      } else {
        ////不能更新,则需求先移出原有child,再创立新的child并增加
        deactivateChild(child);
        assert(child._parent == null);
        newChild = inflateWidget(newWidget, newSlot);
      }
    } else {
      ///本来没有child ,直接创立新的child,并增加
      newChild = inflateWidget(newWidget, newSlot);
    }
    return newChild;
  }

widget.canUpdate是判别是否可更新,主要经过判别runtimeType和key是否相同,所以咱们想强制更新时就能够指定不同的key,官方不引荐更改runtimeType

If the parent wishes to change the runtimeType or key of the widget at this location in the tree, can do so by unmounting this element and inflating the new widget at this location.

activate

将element的render object从头增加到rendertree中

void activate() {
    assert(_debugLifecycleState == _ElementLifecycle.inactive);
    assert(widget != null);
    assert(owner != null);
    assert(depth != null);
    assert(!_active);
    final bool hadDependencies = (_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)
      owner.scheduleBuildFor(this);
    if (hadDependencies)
      didChangeDependencies();
}

deactivate

在updatechild办法里咱们看到如果新的widget为空而且存在旧的,就会调用deactivateChild移除child,然后调用deactivate办法将_debugLifecycleState 状况置为inactive

///移出element
  @mustCallSuper
  void deactivate() {
    if (_dependencies != null && _dependencies.isNotEmpty) {
      for (final InheritedElement dependency in _dependencies)
        dependency._dependents.remove(this);
    }
    _inheritedWidgets = null;
    _active = false;
  }

unmount

当重制了inheritedwidget和active后,会调用unmount办法,移除该element

结语

好了今日的源码检查就到这了, 作为Flutter届的一个小学生,期望我们多多指教,有问题的当地一起讨论