likes
comments
collection
share

Flutter:element生命周期

作者站长头像
站长
· 阅读数 7

昨天我们讲了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届的一个小学生,希望大家多多指教,有问题的地方一起讨论