Flutter2.*_状态共享
共 3521字,需浏览 8分钟
·
2021-11-16 20:16
提及状态管理,以我们之前介绍的观察者模式来理解,可以轻松一些,特别是对应flutter的eventbus,可以实现跨组件状态同步,状态的持有方进行更新,然后发布状态,使用者们监听状态改变事件,完成一些后续操作。
对于状态共享,存在一个原则:当状态是组件私有的,则这个状态应该由该组件管理。当状态需要跨组件共享时,那么这个状态应该涉及到的跨组件范围内的所有组件的父类来管理,对于跨组件的状态管理,管理方式有很多,前面我们聊到的eventbus便是其中之一。
当然使用软件设计模式里的观察者可以解决我们的处理问题诉求,但是这种设计模式是用来管理状态的最完美的解么?不是的,使用观察者模式时,需要我们每次定义相关事件,然后在widgewt进行初始时,将事件进行注册,相同的在注销时要把所有订阅事件进行事件解绑,这当然不是最优的选择,那么谁才是呢?如果了解之前我们的更新帖子,想必大家会有一个关于使用InheritedWidget的大胆想法,没错,就是依据InheritedWidget的处理思路,flutter提供了provider,即flutetr的跨组件状态管理解决方案!
自定义Provider
定义保存共享数据的InheritedWidget,由于不同业务的数据类型不能预期,所以使用范型接收:
// 一个通用的InheritedWidget,保存需要跨组件共享的状态class InheritedProviderextends 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 ChangeNotifierProviderextends 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 _ChangeNotifierProviderStateextends 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的实际使用,今天的分享就到这里,感谢各位看官捧场,让我们后续研讨学习!