告别回调地狱:HarmonyOS 中用事件总线实现解耦通信
文章目录前言什么是事件总线为啥要用它onSubscribe持续订阅一直在线post发布消息触达所有订阅者onceSubscribe只听一次就走在 aboutToDisappear 中清理订阅完整代码结构回顾写在最后前言近期发现一款很有意思的HarmonyOS 三方库, 地址 pura/harmony-utils(V1.4.0) , 作者是桃花镇童长老, 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦案例demo导航展示↓↓↓↓↓↓接下来言归正传 ↓↓↓↓写 HarmonyOS 应用的时候有没有遇到过这种情况A 页面的某个操作要通知 B 页面更新数据但两个页面之间没有直接的父子关系传参传不过去怎么办这就是事件总线Event Bus大显身手的场景。HarmonyOS 提供了emitter模块而EmitterUtil是对它的封装让使用更简单。这篇文章从零开始带你搞懂onSubscribe、onceSubscribe和post三个最核心的 API。什么是事件总线为啥要用它先说痛点。页面之间通信常见方案有几种路由传参只能传一次页面跳转时用不适合动态通知全局状态需要引入状态管理库适合复杂场景但小需求显得太重回调函数层层传递嵌套深了就变成回调地狱事件总线的思路不一样发布方只管发消息订阅方只管监听两者完全解耦。发布方不知道谁在听订阅方也不关心消息从哪来。在EmitterUtilDemoPage里用了 4 个事件 ID 来演示不同场景// 事件 ID 常量constEVT_NORMALdemo_normal;constEVT_ONCEdemo_once;constEVT_PRIORITYdemo_priority;constEVT_TYPEDdemo_typed;事件 ID 就是消息的频道订阅方和发布方通过相同的 ID 建立连接。onSubscribe持续订阅一直在线onSubscribe是最常用的订阅方式。注册之后只要对应事件发出来回调就会触发不限次数。// aboutToAppear 中注册订阅aboutToAppear(){// onSubscribe —— 持续订阅包装版自动解包 dataEmitterUtil.onSubscribestring(EVT_NORMAL,(msg){this.onSubCount;this.addLog([onSubscribe] 第${this.onSubCount}次 →${msg});});}这里有几点值得注意泛型string的作用告诉 EmitterUtil这个事件传递的数据类型是string。这样回调参数msg就是string类型不需要手动转换用起来很方便。自动解包onSubscribe是封装版回调直接给你数据内容msg就是发送的字符串不需要自己去取data.data。在生命周期中注册aboutToAppear是页面显示前的钩子在这里注册订阅是标准做法。页面一显示就开始监听不会漏掉消息。post发布消息触达所有订阅者有了订阅当然要配合发布。post方法负责发送消息// 点击按钮时发布消息EmitterUtil.poststring(EVT_NORMAL,你好 Emitter,emitter.EventPriority.HIGH);this.addLog([post] EVT_NORMAL 已发送 HIGH);三个参数分别是事件 IDEVT_NORMAL和订阅时的 ID 对应消息内容你好 Emitter这里是字符串也可以是对象优先级可选HIGH表示高优先级会优先处理当post被调用后所有订阅了EVT_NORMAL的回调都会收到这条消息。还可以发低优先级消息EmitterUtil.poststring(EVT_NORMAL,低优先级消息,emitter.EventPriority.LOW);优先级的区别是高优先级的消息会比低优先级的更早被处理在消息量大的场景下有用。onceSubscribe只听一次就走有些场景我们只需要响应一次事件比如等待服务器首次返回结果。这时候用onceSubscribe// 单次订阅只触发一次EmitterUtil.onceSubscribestring(EVT_ONCE,(msg){this.onceSubCount;this.addLog([onceSubscribe] 只收一次 →${msg});});和onSubscribe的区别就一个回调触发一次后自动取消订阅。演示页里专门设计了一个按钮来验证这个行为// 点击发布 EVT_ONCE 事件EmitterUtil.poststring(EVT_ONCE,我只被消费一次);this.addLog([post] EVT_ONCE 已发送再发将不触发回调);你可以多次点击这个按钮会发现第一次点击后onceSubCount变成了 1之后再点日志里只有发送记录回调不会再触发了。这就是onceSubscribe的特性一次性用完即废。在 aboutToDisappear 中清理订阅这是个容易被忽略但非常重要的细节。页面销毁时如果不取消订阅回调依然存在于内存里下次同样的事件发出来已经销毁的页面还会尝试更新 UI轻则内存泄漏重则直接崩溃。aboutToDisappear(){// 退出页面时清理订阅EmitterUtil.unSubscribe(EVT_NORMAL);EmitterUtil.unSubscribe(EVT_ONCE);EmitterUtil.offstring(EVT_TYPED);}规则很简单在aboutToAppear里订阅就在aboutToDisappear里取消成对出现不遗漏。完整代码结构回顾结合演示页一个完整的 EmitterUtil 使用流程是这样的EntryComponentstruct EmitterUtilDemoPage{StateonSubCount:number0;StateonceSubCount:number0;aboutToAppear(){// 1. 持续订阅EmitterUtil.onSubscribestring(EVT_NORMAL,(msg){this.onSubCount;this.addLog([onSubscribe] 第${this.onSubCount}次 →${msg});});// 2. 单次订阅EmitterUtil.onceSubscribestring(EVT_ONCE,(msg){this.onceSubCount;this.addLog([onceSubscribe] 只收一次 →${msg});});}aboutToDisappear(){EmitterUtil.unSubscribe(EVT_NORMAL);EmitterUtil.unSubscribe(EVT_ONCE);}}写在最后EmitterUtil 的核心思路就三步订阅 → 发布 → 清理。用onSubscribe持续监听用onceSubscribe一次性监听用post发送消息页面销毁时用unSubscribe清理掌握这三步组件间通信的大部分场景都能搞定。下一篇我们聊聊更高级的用法精准取消订阅和订阅数量统计。