美文网首页Flutter随笔
Flutter局部状态管理

Flutter局部状态管理

作者: 嘛尼嘛哄 | 来源:发表于2020-09-15 08:27 被阅读0次

    局部状态管理

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

    InheritedWidget

    • 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();
      }
    }
    
    

    代码实现

    
    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局部状态管理

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