封裝flutter狀態(tài)管理工具示例詳解
引言
關(guān)于 Flutter 狀態(tài)管理,公司項(xiàng)目使用的是Bloc
方案。Bloc 其實(shí)本質(zhì)上是 provider
的封裝擴(kuò)展庫,整體通過 InheritedWidget
、Notifier
外加 Stream
中轉(zhuǎn)實(shí)現(xiàn)狀態(tài)變更通知。
關(guān)于 Bloc 實(shí)現(xiàn)原理,有興趣的同學(xué)可以觀看這篇文章 Bloc原理解析
RxBinder
撇開Bloc
內(nèi)部實(shí)現(xiàn)策略,小轟嘗試基于數(shù)據(jù)驅(qū)動模型,自定義一套狀態(tài)管理工具。構(gòu)思如下:
主要成員如下:
RxBinderData
: 數(shù)據(jù)模型基類,內(nèi)部封裝變更通知RxBinder
: 核心類,用于關(guān)聯(lián)訂閱關(guān)系
代碼實(shí)現(xiàn)
創(chuàng)建一個(gè)工具類用于注冊和發(fā)送通知
///使用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(); } } }
數(shù)據(jù)模型應(yīng)該具備兩個(gè)特性:當(dāng)數(shù)據(jù)被使用時(shí),添加監(jiān)聽;當(dāng)數(shù)據(jù)發(fā)生改變時(shí)發(fā)送變更通知。
///數(shù)據(jù)模型基類,(封裝變更通知) 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 { //添加監(jiān)聽,變更通知注冊 _rxBinder?.register(uuid, subject); return _value; } set value(T val) { _value = val; notify(); } void notify() { //通知數(shù)據(jù)發(fā)生變更 subject.notify(); } }
創(chuàng)建一個(gè)中轉(zhuǎn)工具類,用于統(tǒng)一管理數(shù)據(jù)變更時(shí)的消息分發(fā)和訂閱關(guān)系
class RxBinder { Map<RxNotifier, String> _subjects = {}; ///訂閱者, key是訂閱的數(shù)據(jù)id, value是訂閱數(shù)據(jù)發(fā)生變化時(shí)的通知回調(diào) Map<String, List<VoidCallback>> _subscriber = {}; //注冊 void register(String uuid, RxNotifier subject) { if (!_subjects.containsKey(subject)) { subject.addListener(() { _notify(uuid); }); _subjects[subject] = ''; } } //添加訂閱關(guān)系 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) { //數(shù)據(jù)源綁定Rx entity.bindRx(rxBinder); rxBinder.addListener(entity.uuid, notifyDataChange); } } void notifyDataChange() { setState(() {}); } @override Widget build(BuildContext context) { return widget.builder(context); } }
Demo 完美運(yùn)行
///基礎(chǔ)數(shù)據(jù)類型以int作為栗子 extension IntExtension on int { RxInt get rex => RxInt(this); //綁定Rx通知 void bindRx(RxBinder? value) { rex.bindRx(value); } } ///具體業(yè)務(wù)的擴(kuò)展類 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( '點(diǎn)擊了 ${logic.count.value} 次', ); } }
以上就是封裝flutter狀態(tài)管理工具示例詳解的詳細(xì)內(nèi)容,更多關(guān)于flutter狀態(tài)管理封裝的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android 擴(kuò)大 View 的點(diǎn)擊區(qū)域的方法
這篇文章主要介紹了Android 擴(kuò)大 View 的點(diǎn)擊區(qū)域的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04Android異常 java.lang.IllegalStateException解決方法
這篇文章主要介紹了Android異常 java.lang.IllegalStateException解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Android開發(fā)使用WebView打造web app示例代碼
這篇文章主要介紹了Android開發(fā)使用WebView打造web app的關(guān)鍵示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03Android仿拉手網(wǎng)團(tuán)購App我的收藏界面實(shí)例代碼
這篇文章主要介紹了Android仿拉手團(tuán)購網(wǎng)App我的收藏界面實(shí)例代碼,需要的朋友可以參考下2017-05-05Android仿淘寶頭條基于TextView實(shí)現(xiàn)上下滾動通知效果
這篇文章主要介紹了Android TextView實(shí)現(xiàn)上下滾動通知效果,需要的朋友可以參考下2017-03-03Android Jetpack 狠活Lifecycles與LiveData使用詳解
這篇文章主要為大家介紹了Android Jetpack 狠活Lifecycles與LiveData使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Android實(shí)現(xiàn)EditText控件禁止輸入內(nèi)容的方法(附測試demo)
這篇文章主要介紹了Android實(shí)現(xiàn)EditText控件禁止輸入內(nèi)容的方法,涉及Android針對EditText控件屬性設(shè)置的相關(guān)技巧,需要的朋友可以參考下2015-12-12Android實(shí)現(xiàn)TextView兩端對齊的方法
這篇文章主要介紹了Android實(shí)現(xiàn)TextView兩端對齊的方法,需要的朋友可以參考下2016-01-01