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

posted @ 2020-10-09 11:54  阿甘左  阅读(348)  评论(0编辑  收藏  举报