美文网首页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