網站首頁 編程語言 正文
引言
關于 Flutter 狀態管理,公司項目使用的是Bloc
方案。Bloc 其實本質上是 provider
的封裝擴展庫,整體通過 InheritedWidget
、Notifier
外加 Stream
中轉實現狀態變更通知。
關于 Bloc 實現原理,有興趣的同學可以觀看這篇文章 Bloc原理解析
RxBinder
撇開Bloc
內部實現策略,小轟嘗試基于數據驅動模型,自定義一套狀態管理工具。構思如下:
主要成員如下:
-
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(); } } }
數據模型應該具備兩個特性:當數據被使用時,添加監聽;當數據發生改變時發送變更通知。
///數據模型基類,(封裝變更通知) 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(); } }
創建一個中轉工具類,用于統一管理數據變更時的消息分發和訂閱關系
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} 次', ); } }
原文鏈接:https://juejin.cn/post/7012537281726644254
相關推薦
- 2022-11-11 利用Python程序讀取Excel創建折線圖_python
- 2022-04-23 如何在vs-code 中進行debugger調試
- 2022-05-23 一起來學習C++的函數指針和函數對象_C 語言
- 2022-12-09 c++利用vector創建二維數組的幾種方法總結_C 語言
- 2022-11-09 Golang中字符串(string)與字節數組([]byte)一行代碼互轉實例_Golang
- 2022-11-08 Python?Panda中索引和選擇?series?的數據_python
- 2022-11-06 SQL?Server?Reporting?Services?匿名登錄的問題及解決方案_MsSql
- 2022-08-21 python深度學習tensorflow實例數據下載與讀取_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支