封裝flutter狀態(tài)管理工具示例詳解
引言
關(guān)于 Flutter 狀態(tài)管理,公司項(xiàng)目使用的是Bloc方案。Bloc 其實(shí)本質(zhì)上是 provider 的封裝擴(kuò)展庫(kù),整體通過(guò) 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ū)動(dòng)模型,自定義一套狀態(tài)管理工具。構(gòu)思如下:

主要成員如下:
RxBinderData: 數(shù)據(jù)模型基類,內(nèi)部封裝變更通知RxBinder: 核心類,用于關(guān)聯(lián)訂閱關(guān)系
代碼實(shí)現(xiàn)
創(chuàng)建一個(gè)工具類用于注冊(cè)和發(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)聽,變更通知注冊(cè)
_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 = {};
//注冊(cè)
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)管理封裝的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Flutter在項(xiàng)目中使用動(dòng)畫不使用包實(shí)現(xiàn)詳解
- Flutter繪制3.4邊形及多邊形漸變動(dòng)畫實(shí)現(xiàn)示例
- Flutter添加頁(yè)面過(guò)渡動(dòng)畫實(shí)現(xiàn)步驟
- Flutter學(xué)習(xí)LogUtil封裝與實(shí)現(xiàn)實(shí)例詳解
- flutter封裝單選點(diǎn)擊菜單工具欄組件
- flutter封裝點(diǎn)擊菜單工具欄組件checkBox多選版
- 基于fluttertoast實(shí)現(xiàn)封裝彈框提示工具類
- Flutter封裝組動(dòng)畫混合動(dòng)畫AnimatedGroup示例詳解
相關(guān)文章
Android編程實(shí)現(xiàn)圖片背景漸變切換與圖層疊加效果
這篇文章主要介紹了Android編程實(shí)現(xiàn)圖片背景漸變切換與圖層疊加效果,涉及Android圖形特效的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2017-01-01
Android實(shí)現(xiàn)Gesture手勢(shì)識(shí)別用法分析
這篇文章主要介紹了Android實(shí)現(xiàn)Gesture手勢(shì)識(shí)別用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android基于Gesture實(shí)現(xiàn)手勢(shì)識(shí)別的原理與具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-09-09
Android 快速實(shí)現(xiàn)狀態(tài)欄透明樣式的示例代碼
下面小編就為大家分享一篇Android 快速實(shí)現(xiàn)狀態(tài)欄透明樣式的示例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
詳解Android Activity之間跳轉(zhuǎn)出現(xiàn)短暫黑屏的處理方法
本篇文章主要介紹了詳解Android Activity之間跳轉(zhuǎn)出現(xiàn)短暫黑屏的處理方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-06-06
Android項(xiàng)目中引入aar包的正確方法介紹
生成aar之后下一步就是如何引用本地的aar文件,下面這篇文章主要給大家介紹了關(guān)于Android項(xiàng)目中引入aar包的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
Android中Item實(shí)現(xiàn)點(diǎn)擊水波紋效果
這篇文章主要給大家介紹了關(guān)于Android中Item實(shí)現(xiàn)點(diǎn)擊水波紋效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
Android模糊處理簡(jiǎn)單實(shí)現(xiàn)毛玻璃效果
這篇文章主要介紹了Android模糊處理簡(jiǎn)單實(shí)現(xiàn)毛玻璃效果的相關(guān)資料,需要的朋友可以參考下2016-02-02
RxJava+Retrofit+OkHttp實(shí)現(xiàn)文件上傳
本篇文章主要介紹了RxJava+Retrofit+OkHttp實(shí)現(xiàn)文件上傳,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11

