美文网首页Flutter随笔
Flutter Element笔记

Flutter Element笔记

作者: 嘛尼嘛哄 | 来源:发表于2020-09-16 07:32 被阅读0次

Element主要分为2类

  1. ComponentElement: 合成其它的Element, 它的子类又StatelessElement,StatefulElement,ProxyElement, 其中StatelessElement和StatefulElement主要用于组建有状态和无状态的widget,ProxyElement则是用于更新依赖,传递数据,局部状态管理。
  2. RenderObjectElement
    提供RenderObject的配置信息,用于创建对应结点的RenderObject

Element家族图普

DiagnosticableTree (diagnostics.dart)
    Element (framework.dart)
        ComponentElement (framework.dart)
            StatelessElement (framework.dart)
            StatefulElement (framework.dart)
            ProxyElement (framework.dart)
                InheritedElement (framework.dart)
                ParentDataElement (framework.dart)
        RenderObjectElement (framework.dart)
            SliverMultiBoxAdaptorElement (sliver.dart)
                _SliverPrototypeExtentListElement (sliver_prototype_extent_list.dart)
            _TableElement (table.dart)
            _LayoutBuilderElement (layout_builder.dart)
            ListWheelElement (list_wheel_scroll_view.dart)
            _SliverPersistentHeaderElement (sliver_persistent_header.dart)
            _CupertinoAlertRenderElement (action_sheet.dart)
            _CupertinoDialogRenderElement (dialog.dart)
            _RenderDecorationElement (input_decorator.dart)
            _ListTileElement (list_tile.dart)
            _RenderChipElement (chip.dart)
            SingleChildRenderObjectElement (framework.dart)
                _OffstageElement (basic.dart)
                _SliverOffstageElement (sliver.dart)
            MultiChildRenderObjectElement (framework.dart)
                _ViewportElement (viewport.dart)
                _TheatreElement (overlay.dart)
                _TextSelectionToolbarItemsElement (text_selection.dart)
            LeafRenderObjectElement (framework.dart)
            RootRenderObjectElement (framework.dart)
                RenderObjectToWidgetElement (binding.dart)

Element {

  1. 继承于BuildContext, 同时和Widget绑定
    Element > DiagnosticableTree > BuildContext
Element(Widget widget)
StatelessElement createElement() => StatelessElement(this);
  1. slot描述了 Element在Tree的位置,在BuilderOwner装配的时候回根据slot决定Element在tree中的位置
//提供给parentElement,用于确定他在child list中的位置
dynamic get slot => _slot;
int get depth => _depth;

set slot => _slot;
  static int _sort(Element a, Element b) {
    if (a.depth < b.depth)
      return -1;
    if (b.depth < a.depth)
      return 1;
    if (b.dirty && !a.dirty)
      return -1;
    if (a.dirty && !b.dirty)
      return 1;
    return 0;
  }

void mount(Element parent, dynamic newSlot)
  1. 通过BuilderOwner可以对ElementTree中的元素更新
  BuildOwner get owner => _owner;
  ...
    void reassemble() {
    markNeedsBuild();
    visitChildren((Element child) {
      child.reassemble();
    });
  }
  1. 获取当前Element下对应的RenderObject(最近的一个RenderObject)
class Element 
...
RenderObject get renderObject {
    RenderObject result;
    void visit(Element element) {
      assert(result == null); // this verifies that there's only one child
      if (element is RenderObjectElement)
        result = element.renderObject;
      else
        element.visitChildren(visit);
    }
    visit(this);
    return result;
  }

abstract class ComponentElement extends Element
   ...
    @override
  void visitChildren(ElementVisitor visitor) {
    if (_child != null)
      visitor(_child);
  }
  1. 管理Child RenderObject,
  void detachRenderObject() {
    visitChildren((Element child) {
      child.detachRenderObject();
    });
    _slot = null;
  }
  //Add [renderObject] to the render tree at the location specified by [slot].
  void attachRenderObject(dynamic newSlot) {
    assert(_slot == null);
    visitChildren((Element child) {
      child.attachRenderObject(newSlot);
    });
    _slot = newSlot;
  }
  1. Globalkey绑定,缓存带有GlobalKey的Element
  void mount(Element parent, dynamic newSlot)
  ......
  if (key is GlobalKey) {
      key._register(this);
    }

  void unmount() {
    ...
    if (key is GlobalKey) {
      key._unregister(this);
    }
    ...
  }
  1. Global Key
Element inflateWidget(Widget newWidget, dynamic newSlot) {
    assert(newWidget != null);
    final Key key = newWidget.key;
    if (key is GlobalKey) {
      final Element newChild = _retakeInactiveElement(key, newWidget);
      ...
    }
    final Element newChild = newWidget.createElement();
    ...
  }

总结

  • Element类似是一个装配容器,他同时持有了BuilderOwnerWidget,BuilderOwner指令触发Element树的构建,在构建过程中它回读取Widget的配置信息,生成在Element树中的节点,同时也提供了也控制着对应的RenderObjet的绑定操作。
  • BuilderOwner(TimeSync) -> Element(Widget)Tree -> RenderObject -> RenderTree

BuildContext

  • 用于定位widget在widget tree中的位置,
  • 通过widge树的层级关系,生成一个对应位置的Element树,具体可以参照 Element类中更新slotdepth的相关方法
  • 相关属性介绍:
//当前Context的配置信息
Widget get widget;
//当前Context的builderOwner,用于管理当前Context的渲染管道
BuildOwner get owner;
//用于查找当前关联的widget的 renderObject,如果找不到就找到下一级最近的
RenderObject findRenderObject();
//通过findRenderObject查找到的RenderObject在窗口中的大小
Size get size;
//注册当前的buildContext到它的上一级的BuildContext中,当`anccestor`的widget变化时会触发当前这个buildContext rebuilt方法
//返回值 InheritedWidget是ancestor.widget
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });
//返回当前Context最近的一个`InheritedWidget`
T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object aspect });

ComponentElement

  • 组成其他的Eleemnt元素
  • mountperformRebuild方法中构建新的Widget,并生成 _child element

StatelessElement

  • 主要重写了buildupdate方法,widget更新检测,
  • build时将当前的BuildContext传递给widget
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();
  }
}

StatefulElement

  • 它是一个包含StatefulWidget配置信息的Element
  • 它比StatelessElement中多了一个State,在reassemble,_firstBuild,performRebuild,activate,deactivate,unmount中进行依赖更新
class StatefulElement extends ComponentElement {
  //根据给定的StatefulWidget配置信息创建Element
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
    _state._widget = widget;
  ...
  
  //构建对应state状态的widget
  @override
  Widget build() => _state.build(this);

  @override
  void reassemble() {
    state.reassemble();  //state重建
    super.reassemble();
  }

  @override
  void _firstBuild() {
     _state.didChangeDependencies();
    super._firstBuild();
  }

  @override
  void performRebuild() {
    if (_didChangeDependencies) {
      _state.didChangeDependencies();
      _didChangeDependencies = false;
    }
    super.performRebuild();
  }

  @override
  void update(StatefulWidget newWidget) {
    super.update(newWidget);
    final StatefulWidget oldWidget = _state._widget;
    ...
    rebuild();
  }

  @override
  void activate() {
    super.activate();
    assert(_active); // otherwise markNeedsBuild is a no-op
    markNeedsBuild();
  }

  @override
  void deactivate() {
    _state.deactivate();
    super.deactivate();
  }
  
  //Element移除时,释放state资源
  @override
  void unmount() {
    super.unmount();
    _state.dispose();
    _state._element = null;
    _state = null;
  }

 
  @override
  InheritedWidget inheritFromElement(Element ancestor, { Object aspect }) {
    return dependOnInheritedElement(ancestor, aspect: aspect);
  }

  @override
  InheritedWidget dependOnInheritedElement(Element ancestor, { Object aspect }) {
    ...
    return super.dependOnInheritedElement(ancestor as InheritedElement, aspect: aspect);
  }

  //依赖更新
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _didChangeDependencies = true;
  }
}

ProxyElement

  • 相比较StatelessElement,多了一个notifyClients方法,
abstract class ProxyElement extends ComponentElement 
...
  void update(ProxyWidget newWidget) {
    final ProxyWidget oldWidget = widget;
     ..
    updated(oldWidget);
     ...
    rebuild();
  }
void updated(covariant ProxyWidget oldWidget) {
    notifyClients(oldWidget);
  }

ParentDataElement

区别在于如果是ParentDataElement会调用所有的child._updateParentData
所有的child都能更新

class ParentDataElement<T extends ParentData> extends ProxyElement {
  ...
    void notifyClients(ParentDataWidget<T> oldWidget) {
    _applyParentData(widget);
  }
  ...
  void _applyParentData(ParentDataWidget<T> widget) {
    void applyParentDataToChild(Element child) {
      if (child is RenderObjectElement) {
        child._updateParentData(widget);
      } else {
        assert(child is! ParentDataElement<ParentData>);
        child.visitChildren(applyParentDataToChild);
      }
    }
    visitChildren(applyParentDataToChild);
  }

InheritedElement

  • 一个使用InheriteWidget作为它的配置信息的Element
  • 初始化
class InheritedElement extends ProxyElement {
  /// Creates an element that uses the given widget as its configuration.
  InheritedElement(InheritedWidget widget) : super(widget);
  • 内部持有一个Map<Element, Object>_dependents,用于缓存对应Element的依赖数据
Map<Element, Object> _dependents = HashMap<Element, Object>();
...
  @protected
  Object getDependencies(Element dependent) {
    return _dependents[dependent];
  }
    @protected
  void setDependencies(Element dependent, Object value) {
    _dependents[dependent] = value;
  }
    @protected
  void updateDependencies(Element dependent, Object aspect) {
    setDependencies(dependent, null);
  }
   @protected
  void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
    dependent.didChangeDependencies();
  }
    @override
  void updated(InheritedWidget oldWidget) {
    if (widget.updateShouldNotify(oldWidget))
      super.updated(oldWidget);
  }
    @override
  void notifyClients(InheritedWidget oldWidget) {
      ...
      notifyDependent(oldWidget, dependent);
    }
  }
  

update widget -> notifiyClients -> notifyDependent -> didChangeDependencies

  • 缓存所有InheritedElement,会将父类的_inheritedWidget一起拿过来
@override
  void _updateInheritance() {
    assert(_active);
    final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;
    if (incomingWidgets != null)
      _inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets);
    else
      _inheritedWidgets = HashMap<Type, InheritedElement>();
    _inheritedWidgets[widget.runtimeType] = this;
  }

RenderObjectElement

  • 一个使用RenderObjectWidget作为配置信息的Element在Element装配的时候会创建RenderObject
  • 同时会将RenderObjet放入到指定的slot中,生成RenderTree
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
     ...
    _renderObject = widget.createRenderObject(this);
     attachRenderObject(newSlot);
     ...
  • 主要api解析
//通过递归调用 `ancestor._parent`(Element中_parent)来获取anestor `RenderObjectElemenet`
  RenderObjectElement _findAncestorRenderObjectElement() {
    Element ancestor = _parent;
    while (ancestor != null && ancestor is! RenderObjectElement)
      ancestor = ancestor._parent;
    return ancestor as RenderObjectElement;
  }
  //同上,递归调用获取anccestor为`ParenetDataElement<ParentData>`的Element
  ParentDataElement<ParentData> _findAncestorParentDataElement()

  mount(Element parent, dynamic newSlot)
  unmount()
  update(covariant RenderObjectWidget newWidget) 
  _updateSlot(dynamic newSlot) 
  performRebuild
  //用于MultiRenderObject来更新数据
  List<Element> updateChildren(List<Element> oldChildren, List<Widget> newWidgets, { Set<Element> forgottenChildren })
  attachRenderObject(dynamic newSlot)
  _updateParentData

RootRenderObjectElement>RenderObjectElement

  • 指定一个BuilderOwner,用于管理ElementTree,RenderTree
RootRenderObjectElement(RenderObjectWidget widget) : super(widget);
mount(Element parent, dynamic newSlot) 

LeafRenderObjectElement>RenderObjectElement

  • 无法进行增删改,在RenderTree的末端
forgetChild(Element child)
insertChildRenderObject(RenderObject child, dynamic slot)
moveChildRenderObject(RenderObject child, dynamic slot) 
removeChildRenderObject(RenderObject child)

SingleChildRenderObjectElement > RenderObjectElement

  • 只有一个RenderObject的Element,无法移动RenderObject层级,因为当前层级只有它一个
visitChildren(ElementVisitor visitor)
forgetChild(Element child)
mount(Element parent, dynamic newSlot)
update(SingleChildRenderObjectWidget newWidget) 
insertChildRenderObject(RenderObject child, dynamic slot)
//无法移动
 void moveChildRenderObject(RenderObject child, dynamic slot) {
    assert(false);
  }
removeChildRenderObject(RenderObject child)

MultiChildRenderObjectElement > RenderObjectElement

  • 一个使用MultiChildRenderObjectWidget配置的Element
  • 主要用于管理它的child renderObject在 renderTree中的位置
MultiChildRenderObjectWidget get widget => super.widget as MultiChildRenderObjectWidget;
Iterable<Element> get children => _children.where((Element child) => !_forgottenChildren.contains(child));
insertChildRenderObject(RenderObject child, IndexedSlot<Element> slot)
moveChildRenderObject(RenderObject child, IndexedSlot<Element> slot)
removeChildRenderObject(RenderObject child)
visitChildren(ElementVisitor visitor)
forgetChild(Element child)
mount(Element parent, dynamic newSlot)
update(MultiChildRenderObjectWidget newWidget)

相关文章

网友评论

    本文标题:Flutter Element笔记

    本文链接:https://www.haomeiwen.com/subject/kkptyktx.html