【Flutter】廣播機制


在APP中,我們經常會需要一個廣播機制,用以跨頁面事件通知,比如一個需要登錄的APP中,頁面會關注用戶登錄或注銷事件,來進行一些狀態更新。這時候,一個事件總線便會非常有用,事件總線通常實現了訂閱者模式,訂閱者模式包含發布者和訂閱者兩種角色,可以通過事件總線來觸發事件和監聽事件,本節我們實現一個簡單的全局事件總線,我們使用單例模式,代碼如下:

//訂閱者回調簽名
typedef void EventCallback(arg);

class EventBus {
  //私有構造函數
  EventBus._internal();

  //保存單例
  static EventBus _singleton = new EventBus._internal();

  //工廠構造函數
  factory EventBus()=> _singleton;

  //保存事件訂閱者隊列,key:事件名(id),value: 對應事件的訂閱者隊列
  var _emap = new Map<Object, List<EventCallback>>();

  //添加訂閱者
  void on(eventName, EventCallback f) {
    if (eventName == null || f == null) return;
    _emap[eventName] ??= new List<EventCallback>();
    _emap[eventName].add(f);
  }

  //移除訂閱者
  void off(eventName, [EventCallback f]) {
    var list = _emap[eventName];
    if (eventName == null || list == null) return;
    if (f == null) {
      _emap[eventName] = null;
    } else {
      list.remove(f);
    }
  }

  //觸發事件,事件觸發后該事件所有訂閱者會被調用
  void emit(eventName, [arg]) {
    var list = _emap[eventName];
    if (list == null) return;
    int len = list.length - 1;
    //反向遍歷,防止在訂閱者在回調中移除自身帶來的下標錯位 
    for (var i = len; i > -1; --i) {
      list[i](arg);
    }
  }
}

//定義一個top-level變量,頁面引入該文件后可以直接使用bus
var bus = new EventBus();

  

使用

//頁面A中
...
 //監聽登錄事件  ——  寫在監聽事件里
 @override
  void initState() {
    super.initState();
    //監聽登錄事件
    bus.on("icon", (arg) {
      print('我試試');
      setState(() {
        _tabIndex = 2;
      });
    });
  }

 

 @override
  void dispose() {
    super.dispose();
    bus.off("icon");//移除廣播機制
  }

 




//登錄頁B中
...
//登錄成功后觸發登錄事件,頁面A中訂閱者會被調用
bus.emit("icon", userInfo);

  

注意:Dart中實現單例模式的標准做法就是使用static變量+工廠構造函數的方式,這樣就可以保證new EventBus()始終返回都是同一個實例,讀者應該理解並掌握這種方法。

事件總線通常用於Widget之間狀態共享,但關於Widget之間狀態共享也有一些專門的Package如redux,這和web框架Vue/React是一致的。通常情況下事件總線是足以滿足業務需求的,如果你決定使用redux的話,一定要想清楚業務是否真的有必要用它,防止“化簡為繁”、過度設計。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM