• Flutter局部状态管理


    • Flutter局部状态管理是通过注册Element依赖实现, 为此构造了InheritedWidgetInheritedModel来实现数据状态管理。
    • InheritedWidget中内部包括了一个泛型的data类型, 用于接受数据, 它本身是一个StatefulWidget, 用于包装child并为child提供数据, 这样以 InheritedWidget 下所有的子节点就能访问它的 data .

    InheritedWidget介绍

    • 继承关系介绍

    如前面所说, 它其实对子widget进行了一次包装, 提供data, (ProxyWidget定义了如何包装widget)
    InheritedWidget > ProxyWidget > Widget

    • 主要方法介绍

    在widget树创建的时候, 会通过BuilderOwner创建 InheritedElement , 由 InheritedElement 来管理它的数据
    同时提供了一个方法用于确定是否需要更新子视图, 具体逻辑由 InheritedElement 实现, InheritedElement 继承于 Element

      InheritedElement createElement() => InheritedElement(this);
      bool updateShouldNotify(covariant InheritedWidget oldWidget);
    
    • 获取数据并注册监听, InheritedElement 实现, InheritedElement 继承于 Element
    //子视图向 `InheritedWidget` 中注册监听事件
    class Element{ 
      
      //用于缓存当前Element节点以及向上查找所有InheritedWidget,保存他们的的Element元素
      Map<Type, InheritedElement> _inheritedWidgets;  
      Set<InheritedElement> _dependencies;
        ....
      @override
      T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) {
        assert(_debugCheckStateIsActiveForAncestorLookup());
        //获取对应的InheritedElement,通过element又能获取对应的widget,这样就能拿到新的数据了
        final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
        if (ancestor != null) {
          assert(ancestor is InheritedElement);
          return dependOnInheritedElement(ancestor, aspect: aspect) as T;
        }
        _hadUnsatisfiedDependencies = true;
        return null;
      }
       
       //承接上面的方法,在每次获取数据的时候都会向当前的指定IheritedWidget(ExactType<XXXInheritedWidget>)注册依赖,这样每当这个InheritedWidget有数据更新时就会接收到通知。
        @override
      InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {
        assert(ancestor != null);
        _dependencies ??= HashSet<InheritedElement>();
        _dependencies.add(ancestor);
    
        //this为当前的订阅者,将它传递给Inherited ancestor.
        ancestor.updateDependencies(this, aspect);
        return ancestor.widget;
      }
     
    class InheritedElement extends ProxyElement {
        ...
       //每个InheritedElement都会更新 `_inheritedWidgets` ,确保从它开始到rootWidget所有的_inheritedWidgets引用都能获取到
        @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;
      }
        //保存对应的aspect,这个在InheritedElement中暂时用不到,默认都为null,是为了个InheritedModel使用
       final Map<Element, Object> _dependents = HashMap<Element, Object>();
      @protected
      void setDependencies(Element dependent, Object value) {
        _dependents[dependent] = value;
      }
    
    • 触发数据更新, 并传递给它的监听者

    首先需要重建 InheritedWidget , 重新修改它的data

    class Element {
       ...
       Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
           ...
          child.update(newWidget);
    }
    
    //更新代理Element
    class ProxyElement extends ComponentElement {
        ...
      void updated(covariant ProxyWidget oldWidget) {
          //通知代理Widget,是否需要更新它的订阅者
        notifyClients(oldWidget);
      }
    }
    
    class InheritedElement extends ProxyElement {
       
         void notifyClients(InheritedWidget oldWidget) { 
          ...
          notifyDependent(oldWidget, dependent);
        }
        //通知子视图重建
          void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
        //此处的dependent及为我们前面所注册的订阅者,标记为dirty执行构建
        dependent.didChangeDependencies();
      }
     
     //重写 `ProxyElement` ,决定是否需要更新
     @override
      void updated(InheritedWidget oldWidget) {
        if (widget.updateShouldNotify(oldWidget))
          super.updated(oldWidget);
      }
    }
    

    关键点: _inheritedWidgets 包含了所有的 InheritedElement 被订阅者, _dependents 包含了当前所有的订阅者

    InheritedModel介绍

    • InheritedModel继承成于InheritedWidget, 实现原理完全相同
    • 相比较 InheritedWidget 它增加了一个标志位的属性, 用于确定在当前的 InheritedModel 中可以选择具体某个属性更新
    abstract class InheritedModel<T> extends InheritedWidget
      @protected
      bool updateShouldNotifyDependent(covariant InheritedModel<T> oldWidget, Set<T> dependencies);
    
      class InheritedModelElement<T> extends InheritedElement {
      /// Creates an element that uses the given widget as its configuration.
      InheritedModelElement(InheritedModel<T> widget) : super(widget);
    
      @override
      InheritedModel<T> get widget => super.widget as InheritedModel<T>;
    
      @override
      void updateDependencies(Element dependent, Object aspect) {
         ...
          setDependencies(dependent, (dependencies ?? HashSet<T>())..add(aspect as T));
      }
    
      @override
      void notifyDependent(InheritedModel<T> oldWidget, Element dependent) {
        //获取当前订阅者指定的标志位 `aspect`
        final Set<T> dependencies = getDependencies(dependent) as Set<T>;
        if (dependencies == null)
          return;
        if (dependencies.isEmpty || widget.updateShouldNotifyDependent(oldWidget, dependencies))
          dependent.didChangeDependencies();
      }
    }
    
    

    示例Demo

    
    import 'package:flutter/material.dart';
    
    class InheritedWidgetDemo extends StatefulWidget {
      @override
      _InheritedWidgetDemoState createState() => _InheritedWidgetDemoState();
    }
    
    class _InheritedWidgetDemoState extends State<InheritedWidgetDemo> {
    
      int middleCount = 0;
    
      int bottomCount = 0;
    
      @override
      void initState() {
        super.initState();
        print('_InheritedWidgetDemoState init');
      }
    
      @override
      Widget build(BuildContext context) {
        context.findAncestorStateOfType<_InheritedWidgetDemoState>();
        return Container(
          child: Column(
            children: <Widget>[
              StateLessWidgetA(),
              GestureDetector(
                child: SharedDataInheritedWidget(
                data: middleCount,
                child: SharedDataInheritedWidgetContainer(),
              ),
              onTap: (){
               middleCount++;
               setState(() {
                 
               });
              },
              ),
              GestureDetector(
                child: SharedDataInheritedModel(
                first: bottomCount,
                second: 2,
                third: 3,
                child: SharedDataInheritedModelContainer(),
              ),
              onTap: (){
                bottomCount++;
                setState(() {
                  
                });
              },
              ),
            ],
          ),
        );
      }
    
      void onTap() {
        print('onTap ......');
      }
    }
    
    class StateLessWidgetA extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        print('StateLessWidgetA build');
        return Padding(
          padding: EdgeInsets.all(20.0),
          child: Text('StateLessWidgetA'),
        );
      }
    }
    
    //// ======= InheritedWidget ========  ////
    class SharedDataInheritedWidget extends InheritedWidget {
      final int data;
      SharedDataInheritedWidget({this.data, Widget child}) : super(child: child);
    
      @override
      bool updateShouldNotify(SharedDataInheritedWidget oldWidget) {
        return this.data != oldWidget.data;
      }
    
      static SharedDataInheritedWidget of(BuildContext context,
          {bool listener = true}) {
        return listener
            ? context.dependOnInheritedWidgetOfExactType<
                    SharedDataInheritedWidget>() ??
                null
            : context.getElementForInheritedWidgetOfExactType<
                SharedDataInheritedWidget>();
      }
    }
    
    class SharedDataInheritedWidgetContainer extends StatefulWidget {
      @override
      _SharedDataInheritedWidgetContainer createState() =>
          _SharedDataInheritedWidgetContainer();
    }
    
    class _SharedDataInheritedWidgetContainer
        extends State<SharedDataInheritedWidgetContainer> {
      @override
      Widget build(BuildContext context) {
        final data = SharedDataInheritedWidget.of(context).data;
        print('StateLessWidgetB build');
        return Padding(
          padding: EdgeInsets.all(20.0),
          child: Text('StateLessWidgetB :$data'),
        );
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        print('_SharedDataInheritedWidgetContainer didChangeDependencies');
      }
    }
    
    //// ======= InheritedModel ==========  ////
    enum ShareDataDependent {
      one,
      two,
      three,
    }
    
    class SharedDataInheritedModel extends InheritedModel {
      final int first;
      final int second;
      final int third;
      final Widget child;
      SharedDataInheritedModel({this.first, this.second, this.third, this.child})
          : super(child: child);
    
      @override
      bool updateShouldNotify(SharedDataInheritedModel oldWidget) {
        return first != oldWidget.first ||
            second != oldWidget.second ||
            third != oldWidget.third;
      }
    
      @override
      bool updateShouldNotifyDependent(
          SharedDataInheritedModel oldWidget, Set dependencies) {
        return first != oldWidget.first &&
                dependencies.contains(ShareDataDependent.one) ||
            second != oldWidget.second &&
                dependencies.contains(ShareDataDependent.two) ||
            third != oldWidget.third &&
                dependencies.contains(ShareDataDependent.three);
      }
    
      static SharedDataInheritedModel of(BuildContext context,
          {bool listener = true, ShareDataDependent aspect}) {
        return listener
            ? context.dependOnInheritedWidgetOfExactType<
                    SharedDataInheritedModel>(aspect: aspect) ??
                null
            : context.getElementForInheritedWidgetOfExactType<
                SharedDataInheritedModel>();
      }
    }
    
    class SharedDataInheritedModelContainer extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
     
        final sharedDataInheritedModel = SharedDataInheritedModel.of(context, aspect: ShareDataDependent.one);
        return Container(
          color: Colors.amber[100],
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              Text('1: ${sharedDataInheritedModel.first}'),
              Text('2: ${sharedDataInheritedModel.second}'),
              Text('3: ${sharedDataInheritedModel.third}'),
            ],
          ),
        );
      }
    }
    

    小结

    局部状态管管理主要通过了属性传值和递归查找来完成的,利用了Flutter状态更新机制,通过对InheritedElements的查找合适的Widget取出对应的data,如果需要监听改变再通过Dependencies属性查找的执行notify方法去跟新它的依赖Widget

  • 相关阅读:
    Vmstat主要关注哪些数据?
    Swap是个什么东东?
    Buffers与cached啥区别
    做错的题目——关于构造器返回值
    做错的题目——this的指向
    JS判断一个数是否为质数
    数组扁平化
    JS实现快速排序
    正则实现千分符
    获取鼠标的当前位置
  • 原文地址:https://www.cnblogs.com/wwoo/p/flutter-ju-bu-zhuang-tai-guan-li.html
Copyright © 2020-2023  润新知