Flutter2.*_状态共享

雲海垂钓

共 3521字,需浏览 8分钟

 · 2021-11-16

    提及状态管理,以我们之前介绍的观察者模式来理解,可以轻松一些,特别是对应flutter的eventbus,可以实现跨组件状态同步,状态的持有方进行更新,然后发布状态,使用者们监听状态改变事件,完成一些后续操作。

    对于状态共享,存在一个原则:当状态是组件私有的,则这个状态应该由该组件管理。当状态需要跨组件共享时,那么这个状态应该涉及到的跨组件范围内的所有组件的父类来管理,对于跨组件的状态管理,管理方式有很多,前面我们聊到的eventbus便是其中之一。

    当然使用软件设计模式里的观察者可以解决我们的处理问题诉求,但是这种设计模式是用来管理状态的最完美的解么?不是的,使用观察者模式时,需要我们每次定义相关事件,然后在widgewt进行初始时,将事件进行注册,相同的在注销时要把所有订阅事件进行事件解绑,这当然不是最优的选择,那么谁才是呢?如果了解之前我们的更新帖子,想必大家会有一个关于使用InheritedWidget的大胆想法,没错,就是依据InheritedWidget的处理思路,flutter提供了provider,即flutetr的跨组件状态管理解决方案!

自定义Provider


  

    定义保存共享数据的InheritedWidget,由于不同业务的数据类型不能预期,所以使用范型接收:

// 一个通用的InheritedWidget,保存需要跨组件共享的状态class InheritedProvider extends InheritedWidget {
  InheritedProvider({
    required this.data,
    required Widget child,
  }) : super(child: child);

  final T data;

  @override
  bool updateShouldNotify(InheritedProvider old) {
    //在此简单返回true,则每次更新都会调用依赖其的子孙节点的`didChangeDependencies`。
    return true;
  }}

    数据保存已经完成,接下来需要在数据变化时对InheritedProvider进行重构,那么要处理的问题有两个:

    ·数据变化时如何通知;

    ·重构InheritedProvider的处理由谁来进行;

    数据变化时的通知我们可以使用eventbus来进行,对应于flutter的sdk工具类ChangeNotifier,ChangeNotifier继承自 Listenable,实现来发布-订阅模式,定义结构为:

class ChangeNotifier implements Listenable {
  List listeners=[];
  @override
  void addListener(VoidCallback listener) {
     //添加监听器
     listeners.add(listener);
  }
  @override
  void removeListener(VoidCallback listener) {
    //移除监听器
    listeners.remove(listener);
  }
  
  void notifyListeners() {
    //通知所有监听器,触发监听器回调 
    listeners.forEach((item)=>item());
  }
   
  ... //省略无关代码}

    此时通过Notifier的add*和remove*可以添加移除监听的订阅者,使用notifyListeners()可以触发所有的监听起回调,此时数据通知的处理已经完成,那么重构工作呢?我们可以将要共享的状态放入一个model类中,让其继承自changenotifier,当共享的状态发生变化时,只需调用notifyListeners方法即可通知订阅者们重新构建InheritedProvider,来看一下订阅者类的实现代码:

class ChangeNotifierProvider extends StatefulWidget {
  ChangeNotifierProvider({
    Key? key,
    this.data,
    this.child,
  });

  final Widget child;
  final T data;

  //定义一个便捷方法,方便子树中的widget获取共享数据
  static T of(BuildContext context) {
    final type = _typeOf>();
    final provider =  context.dependOnInheritedWidgetOfExactType>();
    return provider.data;
  }

  @override
  _ChangeNotifierProviderState createState() => _ChangeNotifierProviderState();}
class _ChangeNotifierProviderState extends State> {
  void update() {
    //如果数据发生变化(model类调用了notifyListeners),重新构建InheritedProvider
    setState(() => {});
  }

  @override
  void didUpdateWidget(ChangeNotifierProvider oldWidget) {
    //当Provider更新时,如果新旧数据不"==",则解绑旧数据监听,同时添加新数据监听
    if (widget.data != oldWidget.data) {
      oldWidget.data.removeListener(update);
      widget.data.addListener(update);
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
  void initState() {
    // 给model添加监听器
    widget.data.addListener(update);
    super.initState();
  }

  @override
  void dispose() {
    // 移除model的监听器
    widget.data.removeListener(update);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return InheritedProvider(
      data: widget.data,
      child: widget.child,
    );
  }}

    上述代码于ChangeNotifierProvider中提供静态方法供子类获取widget树中InheritedProvider中保存的共享状态,_ChangeNotifierProviderState类中主要用来监听共享数据改变时重构Widget树,需要注意的是在调用setstate()方法操作的widget.child始终为同一个,因此执行build时,InheritedProvider的child引用的始终是同一个子widget,在对当前widget进行重新build时,widget.child并不会进行重构,即实现了对widget.child的缓存。需要注意的是如果ChangeNotifierProvider父级Widget重新build时,则其传入的child便有可能会发生变化;

    上述即为flutter提供的provider的实现思路,下一天的更新,我们会结合较为经典的购物车功能,来看一下provider的实际使用,今天的分享就到这里,感谢各位看官捧场,让我们后续研讨学习!

浏览 33
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报