封装flutter状态管理工具示例详解

作者:李小轰_Rex 时间:2022-04-17 14:15:56 

引言

关于 Flutter 状态管理,公司项目使用的是Bloc方案。Bloc 其实本质上是 provider 的封装扩展库,整体通过 InheritedWidgetNotifier 外加 Stream中转实现状态变更通知。

关于 Bloc 实现原理,有兴趣的同学可以观看这篇文章 Bloc原理解析

RxBinder

撇开Bloc内部实现策略,小轰尝试基于数据驱动模型,自定义一套状态管理工具。构思如下:

封装flutter状态管理工具示例详解

主要成员如下:

  • RxBinderData: 数据模型基类,内部封装变更通知

  • RxBinder: 核心类,用于关联订阅关系

代码实现

创建一个工具类用于注册和发送通知

///使用callback的形式管理通知
class RxNotifier {
 List<VoidCallback> _listeners = [];
 void addListener(VoidCallback listener) {
   _listeners.add(listener);
 }
 void remove(VoidCallback listener) {
   if (_listeners.contains(listener)) {
     _listeners.remove(listener);
   }
 }
 ///通知
 void notify() {
   if (_listeners.isEmpty) return;
   for (final entry in _listeners) {
     entry.call();
   }
 }
}

数据模型应该具备两个特性:当数据被使用时,添加监听;当数据发生改变时发送变更通知。

封装flutter状态管理工具示例详解

///数据模型基类,(封装变更通知)
class RxBinderData<T> {
 late T _value;
 late String uuid;
 RxNotifier subject = RxNotifier();
 RxBinder? _rxBinder;
 RxBinderData(this._value, {RxBinder? value}) {
   uuid = Uuid().v4();
   bindRx(value);
 }
 void bindRx(RxBinder? value) {
   _rxBinder = value;
 }
 @override
 String toString() {
   return value.toString();
 }
 T get value {
   //添加监听,变更通知注册
   _rxBinder?.register(uuid, subject);
   return _value;
 }
 set value(T val) {
   _value = val;
   notify();
 }
 void notify() {
   //通知数据发生变更
   subject.notify();
 }
}

创建一个中转工具类,用于统一管理数据变更时的消息分发和订阅关系

封装flutter状态管理工具示例详解

class RxBinder {
 Map<RxNotifier, String> _subjects = {};
 ///订阅者, key是订阅的数据id, value是订阅数据发生变化时的通知回调
 Map<String, List<VoidCallback>> _subscriber = {};
 //注册
 void register(String uuid, RxNotifier subject) {
   if (!_subjects.containsKey(subject)) {
     subject.addListener(() {
       _notify(uuid);
     });
     _subjects[subject] = '';
   }
 }
 //添加订阅关系
 void addListener(String uuid, VoidCallback listener) {
   if (!_subscriber.containsKey(uuid)) {
     //key不存在
     _subscriber[uuid] = [listener];
   } else {
     //key已存在
     List<VoidCallback> list = _subscriber[uuid]!;
     if (!list.contains(listener)) {
       list.add(listener);
       _subscriber[uuid] = list;
     }
   }
 }
 //通知订阅者
 void _notify(String uuid) {
   if (_subscriber.containsKey(uuid)) {
     final list = _subscriber[uuid];
     if (list != null && list.isNotEmpty) {
       for (final entry in list) {
         entry.call();
       }
     }
   }
 }
}

控制刷新组件

typedef WidgetCallback = Widget Function(BuildContext context);
class RxBindWidget extends StatefulWidget {
 final WidgetCallback builder;
 final List<RxBinderData> binders;
 const RxBindWidget(this.builder, this.binders, {Key? key}) : super(key: key);
 @override
 _RxBindWidgetState createState() => _RxBindWidgetState();
}
class _RxBindWidgetState extends State<RxBindWidget> {
 RxBinder rxBinder = RxBinder();
 @override
 void initState() {
   super.initState();
   for (final entity in widget.binders) {
     //数据源绑定Rx
     entity.bindRx(rxBinder);
     rxBinder.addListener(entity.uuid, notifyDataChange);
   }
 }
 void notifyDataChange() {
   setState(() {});
 }
 @override
 Widget build(BuildContext context) {
   return widget.builder(context);
 }
}

Demo 完美运行

///基础数据类型以int作为栗子
extension IntExtension on int {
 RxInt get rex => RxInt(this);
 //绑定Rx通知
 void bindRx(RxBinder? value) {
   rex.bindRx(value);
 }
}
///具体业务的扩展类
class RxInt extends RxBinderData<int> {
 RxInt(int value) : super(value);
 RxInt operator +(int other) {
   value = value + other;
   return this;
 }
 RxInt operator -(int other) {
   value = value - other;
   return this;
 }
}
class Logic {
 RxInt count = 0.rex;
 void increase() => ++count;
}
class TestRxBinder extends StatelessWidget {
 final Logic logic = Logic();
 TestRxBinder({Key? key}) : super(key: key);
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     body: Center(
       child: RxBindWidget((context) {
         return _child(context);
       }, [logic.count]),
     ),
     floatingActionButton: FloatingActionButton(
       onPressed: () => logic.increase(),
       child: Icon(Icons.add),
     ),
   );
 }
 Widget _child(BuildContext context) {
   return Text(
     '点击了 ${logic.count.value} 次',
   );
 }
}

封装flutter状态管理工具示例详解

来源:https://juejin.cn/post/7012537281726644254

标签:flutter,状态管理,工具封装
0
投稿

猜你喜欢

  • Android资源文件与层次式导航超详细讲解

    2022-07-14 16:28:22
  • springboot集成本地缓存Caffeine的三种使用方式(小结)

    2021-06-29 07:00:40
  • 详解Spring Data Jpa当属性为Null也更新的完美解决方案

    2022-04-13 03:06:06
  • Java去掉数字字符串开头的0三种方法(推荐)

    2022-05-31 08:04:41
  • java用户名密码验证示例代码分享

    2021-10-14 08:16:14
  • Java原生HttpClient的使用详解

    2022-06-04 16:29:49
  • c# 动态加载dll文件,并实现调用其中的方法(推荐)

    2021-11-10 04:37:34
  • C#中委托的+=和-=深入研究

    2023-05-31 01:00:15
  • Java父线程(或是主线程)等待所有子线程退出的实例

    2022-10-23 16:25:50
  • 详解java 中泛型中的类型擦除和桥方法

    2021-07-10 23:55:08
  • 浅谈基于SpringBoot实现一个简单的权限控制注解

    2022-01-23 16:42:47
  • java 定时器线程池(ScheduledThreadPoolExecutor)的实现

    2023-03-31 20:52:10
  • Android提高之BLE开发Android手机搜索iBeacon基站

    2023-05-19 18:58:15
  • C#递归应用之实现JS文件的自动引用

    2023-12-09 00:03:52
  • java实现归并排序算法

    2023-02-09 07:34:01
  • Spring AOP的概念与实现过程详解

    2023-02-17 02:54:12
  • 利用Matlab复刻羊了个羊小游戏

    2021-10-10 17:13:05
  • WinForm项目开发中Excel用法实例解析

    2022-07-11 10:23:03
  • 如何优雅的进行Spring整合MongoDB详解

    2022-10-23 05:24:19
  • C#实现语音视频录制-附demo源码

    2023-10-04 13:22:03
  • asp之家 软件编程 m.aspxhome.com