美文网首页
flutter InheritedWidget机制

flutter InheritedWidget机制

作者: cg1991 | 来源:发表于2020-05-19 17:49 被阅读0次

    个人网站:chengang.plus

    1、用法

    用法示例:

    class InheritedData extends InheritedWidget {
      final String data;
    
      InheritedData({
        this.data,
        Widget child,
      }) : super(child: child);
    
      static InheritedData of(BuildContext context) {
        return context.dependOnInheritedWidgetOfExactType<InheritedData>();
      }
    
      @override
      bool updateShouldNotify(InheritedData old) => true;
    }
    
    class TestInheritedDataWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Text(
            "${InheritedData.of(context).data}",
            style: TextStyle(fontSize: 18, color: Colors.pink),
          ),
        );
      }
    }
    
    class ParentWidget extends StatefulWidget {
      @override
      _ParentWidgetState createState() => _ParentWidgetState();
    }
    
    class _ParentWidgetState extends State<ParentWidget> {
      var data = "you are beautiful";
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: GestureDetector(
            child: Container(
              color: Colors.cyan,
              width: double.infinity,
              child: InheritedData(
                data: data,
                child: TestInheritedDataWidget(),
              ),
            ),
            onTap: _buttonClicked,
          ),
        );
      }
    
      _buttonClicked() {
        setState(() {
          data = "in white";
        });
      }
    }
    

    2、ProxyWidget

    InheritedWidget继承自ProxyWidget,在ProxyWidget中createElement调用的时候,创建了一个InheritedElement对象。

    2.1 InheritedElement

    InheritedElement继承自ProxyElement,ProxyElement继承自ComponentElement,ComponentElement继承自Element。

    在InheritedElement中定义了一个全局Map对象:

    final Map<Element, Object> _dependents = HashMap<Element, Object>();
    

    同时还定义了一个_updateInheritance方法。在Element和
    InheritedElement中都有定义:

    Element

    void _updateInheritance() {
        _inheritedWidgets = _parent?._inheritedWidgets;
    }
    

    Map<Type, InheritedElement> _inheritedWidgets定义在Element中,是一个全局变量。

    InheritedElement

    @override
    void _updateInheritance() {
        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;
    }
    

    InheritedElement中这个方法的主要逻辑是:先判断当前Element的_inheritedWidgets是否存在,不存在,新建一个,否则将已有的添加到_inheritedWidgets中,同时将当前Element添加到_inheritedWidgets中。

    Element中的_updateInheritance方法被执行意味着,所有的Widget对应的Element都持有一个_inheritedWidgets,而InheritedWidget的child就可以通过Element的_updateInheritance方法直接持有InheritedElement。

    2.2 保存InheritedElement节点

    那么_updateInheritance是哪里调用的呢?

    参考之前的文章《flutter 绘制过程 系列2-布局》,在Element类的mount方法中,会调用_updateInheritance方法,最终就调用到这里了。

    3、ProxyElement中更新

    当InheritedWidget中的data被setState更新之后,依赖data的Widget也会被更新。

    3.1 ProxyElement update方法

    @override
    void update(ProxyWidget newWidget) {
        final ProxyWidget oldWidget = widget;
        super.update(newWidget);
        updated(oldWidget);
        _dirty = true;
        rebuild();
    }
    

    到updated方法,在InheritedElement方法中:

    InheritedElement

    @override
    void updated(InheritedWidget oldWidget) {
        if (widget.updateShouldNotify(oldWidget))
          super.updated(oldWidget);
    }
    

    如果我们InheritedWidget中的updateShouldNotify返回为true的话,会执行到InheritedElement的updated方法中:

    @protected
    void updated(covariant ProxyWidget oldWidget) {
        notifyClients(oldWidget);
    }
    

    notifyClients执行到了子类InheritedElement的notifyClients方法。

    3.2 InheritedElement notifyClients方法

    @override
    void notifyClients(InheritedWidget oldWidget) {
        for (final Element dependent in _dependents.keys) {
          notifyDependent(oldWidget, dependent);
        }
    }
    

    这里的_dependents里面保存的是依赖InheritedWidget数据的节点。

    3.3 _dependents保存依赖数据的Element

    本章最开始的时候InheritedData提供了一个静态的of方法,依赖者(InheritedWidget的child Widget)调用dependOnInheritedWidgetOfExactType方法。在Element类中实现,BuildContext类中定义:

    Element实现了BuildContext接口

    Element

    @override
    T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) {
        final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
        if (ancestor != null) {
          return dependOnInheritedElement(ancestor, aspect: aspect) as T;
        }
        _hadUnsatisfiedDependencies = true;
        return null;
    }
    

    这里先找到InheritedElement,通过_inheritedWidgets的key(runtimeType)找到对应的value(InheritedElement)。接下来调用dependOnInheritedElement方法:

    Element

    @override
    InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {
        _dependencies ??= HashSet<InheritedElement>();
        _dependencies.add(ancestor);
        ancestor.updateDependencies(this, aspect);
        return ancestor.widget;
    }
    

    在Element类中,先判断_dependencies是否为空,为空的话新建一个HashSet,把这个InheritedElement添加进去,然后执行updateDependencies方法。这个this指代的就是InheritedWidget的child Widget的Element。

    这个updateDependencies定义在对应的InheritedElement类中:

    InheritedElement

    @override
    void updateDependencies(Element dependent, Object aspect) {
        final Set<T> dependencies = getDependencies(dependent) as Set<T>;
        if (dependencies != null && dependencies.isEmpty)
          return;
        
        if (aspect == null) {
          setDependencies(dependent, HashSet<T>());
        } else {
          setDependencies(dependent, (dependencies ?? HashSet<T>())..add(aspect as T));
        }
    }
    
    @protected
    void setDependencies(Element dependent, Object value) {
        _dependents[dependent] = value;
    }
    

    到这里基本上清楚了基本的脉络,_dependents里面保存的就是是InheritedWidget的child Widget的Element。

    3.4 提醒依赖Element更新

    回到InheritedElement notifyClients方法,这里会遍历_dependents,然后执行notifyDependent方法:

    InheritedElement

    @protected
    void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
        dependent.didChangeDependencies();
    }
    
    @mustCallSuper
    void didChangeDependencies() {
        markNeedsBuild();
    }
    

    到这里重新绘制渲染依赖InheritedWidget数据的Widget。

    相关文章

      网友评论

          本文标题:flutter InheritedWidget机制

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