flutter插件event_bus(事件總線)封裝

App中歉秫,我們經(jīng)常會(huì)需要實(shí)現(xiàn)廣播機(jī)制葛躏,用以跨頁(yè)面事件通知局齿。事件總線通常實(shí)現(xiàn)了訂閱模式剧劝,訂閱者模式包含了發(fā)布者和訂閱者兩種角色,可以通過事件總線來(lái)觸發(fā)事件和監(jiān)聽事件, 下面我們實(shí)現(xiàn)一個(gè)簡(jiǎn)單的全局事件總線抓歼,使用單例模式讥此。
核心原理就:?jiǎn)卫?+ Map<事件Key,訂閱者列表> + 列表遍歷谣妻,一個(gè)簡(jiǎn)單的實(shí)現(xiàn)代碼示例如下:

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

class EventBus {
  //私有構(gòu)造函數(shù)
  EventBus._internal();

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

  //工廠構(gòu)造函數(shù)
  factory EventBus()=> _singleton;

  //保存事件訂閱者隊(duì)列暂论,key:事件名(id),value: 對(duì)應(yīng)事件的訂閱者隊(duì)列
  final _emap = Map<Object, List<EventCallback>?>();

  //添加訂閱者
  void on(eventName, EventCallback f) {
    _emap[eventName] ??=  <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);
    }
  }

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


//定義一個(gè)top-level(全局)變量,頁(yè)面引入該文件后可以直接使用bus
var bus = EventBus();
//頁(yè)面A中湃窍,監(jiān)聽登錄事件
bus.on("login", (arg) {
  // do something
});

//登錄頁(yè)B中闻蛀,登錄成功后觸發(fā)登錄事件,頁(yè)面A中訂閱者會(huì)被調(diào)用
bus.emit("login", userInfo);

也可以用 dart:async 里的 Stream(流) 來(lái)實(shí)現(xiàn):

import 'dart:async';

class EventBus {
  // 使用多訂閱流的形式您市,這種流可以有多個(gè)監(jiān)聽器監(jiān)聽(
  final _streamController = StreamController.broadcast();

  // 定義一個(gè)單例
  static final EventBus _instance = EventBus._internal();

  factory EventBus() {
    return _instance;
  }

  EventBus._internal();

  // 發(fā)布事件
  void fire(event) {
    _streamController.add(event);
  }

  // 訂閱事件
  StreamSubscription on<T>(void Function(T) onData) {
    return _streamController.stream.where((event) => event is T).listen(onData);
  }
}

// 調(diào)用處:
var eventBus = EventBus();
// 發(fā)布一個(gè)事件
eventBus.fire(UserLoggedInEvent('Alice'));
// 在其他地方訂閱這個(gè)事件:
StreamSubscription subscription = eventBus.on<UserLoggedInEvent>((event) {
  print('User logged in: ${event.username}');
});
//在合適的地方取消訂閱
subscription.cancel();

總體來(lái)說(shuō)觉痛,封裝方式1是一種基于回調(diào)函數(shù)的自定義事件機(jī)制,而封裝方式2是基于 Dart 內(nèi)置的 Stream 和 StreamController 的事件機(jī)制茵休。方式1相對(duì)簡(jiǎn)單薪棒,適用于基本的事件通知需求,而方式2更靈活榕莺、功能更強(qiáng)大俐芯,適用于復(fù)雜的場(chǎng)景,尤其是需要異步事件處理的情況钉鸯。

選擇建議:
如果項(xiàng)目簡(jiǎn)單吧史,不需要支持異步事件,且對(duì)事件系統(tǒng)的需求較為基礎(chǔ)唠雕,封裝方式1是一個(gè)簡(jiǎn)單有效的選擇贸营。

如果項(xiàng)目需要支持異步事件吨述、有復(fù)雜的事件過濾和管理需求,或者需要廣播模式支持多個(gè)監(jiān)聽器钞脂,封裝方式2是更為合適的選擇揣云。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冰啃,隨后出現(xiàn)的幾起案子灵再,更是在濱河造成了極大的恐慌,老刑警劉巖亿笤,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翎迁,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡净薛,警方通過查閱死者的電腦和手機(jī)汪榔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肃拜,“玉大人痴腌,你說(shuō)我怎么就攤上這事∪剂欤” “怎么了士聪?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)猛蔽。 經(jīng)常有香客問我剥悟,道長(zhǎng),這世上最難降的妖魔是什么曼库? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任区岗,我火速辦了婚禮,結(jié)果婚禮上毁枯,老公的妹妹穿的比我還像新娘慈缔。我一直安慰自己,他們只是感情好种玛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布藐鹤。 她就那樣靜靜地躺著,像睡著了一般赂韵。 火紅的嫁衣襯著肌膚如雪娱节。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天右锨,我揣著相機(jī)與錄音括堤,去河邊找鬼。 笑死绍移,一個(gè)胖子當(dāng)著我的面吹牛悄窃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蹂窖,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼轧抗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了瞬测?” 一聲冷哼從身側(cè)響起横媚,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎月趟,沒想到半個(gè)月后灯蝴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡孝宗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年穷躁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片因妇。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡问潭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出婚被,到底是詐尸還是另有隱情狡忙,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布址芯,位于F島的核電站灾茁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谷炸。R本人自食惡果不足惜删顶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淑廊。 院中可真熱鬧逗余,春花似錦、人聲如沸季惩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)画拾。三九已至啥繁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間青抛,已是汗流浹背旗闽。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人适室。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓嫡意,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親捣辆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蔬螟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容