日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

封裝flutter狀態管理工具示例詳解_Android

作者:李小轟_Rex ? 更新時間: 2022-12-12 編程語言

引言

關于 Flutter 狀態管理,公司項目使用的是Bloc方案。Bloc 其實本質上是 provider 的封裝擴展庫,整體通過 InheritedWidgetNotifier 外加 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

欄目分類
最近更新