【HarmonyOS NEXT】EventHub 和 Emitter 的使用场景与区别
一、前言
很多刚学习 HarmonyOS 的同学都会问:
为什么鸿蒙里面既有 EventHub,又有 Emitter?
它们都是事件通信。
到底有什么区别?
什么时候应该使用哪个?
有没有类似 Android EventBus?
有没有类似 Vue EventEmitter?
为什么官方推荐 EventHub,而很多开源项目喜欢用 Emitter?
本文将通过大量实例,把这两个机制彻底讲透。
二、为什么需要事件通信
先来看一个简单场景。
首页:
Home
点击:
修改昵称
进入:
ProfilePage
修改成功以后:
返回首页
首页需要刷新:
昵称
头像
VIP等级
问题来了:
ProfilePage 如何通知 Home?
最简单的方法:
Home.reload()
显然不现实。
因为:
Home
↓
Profile
没有引用
所以需要:
解耦通信
这就是事件机制存在的意义。
三、HarmonyOS 的事件通信方式
HarmonyOS 常见通信方式:
UI状态
@State
↓
父子
@Prop
↓
双向
@Link
↓
跨层级
@Provide
@Inject
↓
应用事件
EventHub
↓
全局事件
Emitter
↓
后台任务
CommonEvent
可以画成:
State
↓
Prop
↓
Link
↓
Provide
↓
EventHub
↓
Emitter
职责越来越大。
四、什么是 EventHub
官方定义:
Ability 内部页面事件中心。
特点:
同一个UIAbility
所有页面共享
生命周期一致
自动管理
例如:
EntryAbility
├── Home
├── Mine
├── Detail
└── Setting
它们:
共享一个 EventHub
五、EventHub 工作原理
实际上:
UIAbility
↓
Context
↓
EventHub
↓
Listener Map
内部可以理解为:
Map<String,List<Function>>
例如:
loginSuccess
↓
[
callback1,
callback2,
callback3
]
emit:
遍历执行
六、获取 EventHub
例如:
let eventHub = this.context.eventHub;
或者:
getContext(this).eventHub
以后:
on
off
emit
都通过它完成。
七、EventHub 常用 API
on()
注册事件:
eventHub.on(
"loginSuccess",
(data)=>{
console.info(data.name)
}
)
emit()
发送:
eventHub.emit(
"loginSuccess",
{
name:"Tom"
}
)
off()
取消:
eventHub.off("loginSuccess")
八、EventHub 生命周期
最大的优势:
生命周期和 Ability 一致。
例如:
Ability退出
所有监听:
全部释放
不用担心:
内存泄漏
九、EventHub 实战一:首页刷新
Home:
aboutToAppear() {
this.context.eventHub.on(
"refresh",
()=>{
this.loadData()
}
)
}
Profile:
this.context.eventHub.emit("refresh")
十、EventHub 实战二:购物车刷新
加入购物车:
Detail
↓
emit
↓
Cart
↓
reload
代码:
eventHub.emit("cartUpdate")
购物车:
eventHub.on("cartUpdate",()=>{
this.queryCart()
})
十一、EventHub 优缺点
优点:
✔ 生命周期安全
✔ Ability级别
✔ 官方推荐
✔ 管理方便
缺点:
只能:
一个Ability内部
不能:
跨Ability
十二、什么是 Emitter
Emitter:
不是 Ability 自带。
它属于:
@ohos.events.emitter
导入:
import emitter from '@ohos.events.emitter'
它是:
系统级事件发送器
更接近:
Node.js
EventEmitter
十三、Emitter 原理
内部也是:
Listener
↓
Map
↓
callback
但是:
全局
而不是:
Ability
十四、Emitter API
发送:
emitter.emit({
eventId:1001
})
监听:
emitter.on(
{
eventId:1001
},
()=>{
}
)
取消:
emitter.off({
eventId:1001
})
十五、Emitter EventId
Emitter 使用:
eventId
例如:
1001
1002
1003
官方建议:
不同模块:
不要重复
可以:
10000
20000
30000
进行划分。
十六、Emitter 数据传递
例如:
emitter.emit({
eventId:1001
},{
data:{
name:"Tom",
age:18
}
})
监听:
emitter.on(
{
eventId:1001
},
(event)=>{
console.info(event.data.name)
}
)
十七、Emitter 使用场景
例如:
SDK通知
↓
播放器
↓
登录状态
↓
下载完成
↓
消息推送
这些:
都适合。
十八、EventHub 与 Emitter 对比
| 对比项 | EventHub | Emitter |
|---|---|---|
| 生命周期 | UIAbility | 全局事件 |
| 管理方式 | Context 持有 | 系统模块 |
| 通信范围 | 同一 UIAbility | 更广泛的应用内模块 |
| API | on/off/emit | on/off/emit |
| 标识方式 | 字符串 | eventId |
| 官方推荐场景 | 页面通信 | 全局事件、系统事件 |
| 自动释放 | 是(随 Ability 生命周期) | 需要开发者主动管理监听 |
| 学习成本 | 低 | 中 |
十九、EventHub 与 Emitter 如何选择
建议遵循以下原则:
使用 EventHub
适用于:
- 同一个 UIAbility 页面之间通信
- 页面刷新
- 登录状态刷新
- 列表更新
- 页面返回通知
例如:
Home
↓
Detail
↓
返回刷新
使用 Emitter
适用于:
- 全局事件中心
- SDK 封装
- 播放器事件
- 下载管理
- WebSocket 消息分发
- 跨业务模块解耦
例如:
Socket
↓
Emitter
↓
聊天页
↓
消息中心
↓
通知模块
二十、最佳实践
建议建立统一的事件管理模块,避免在代码中散落字符串或数字常量。
例如:
export const EventKeys = {
LOGIN_SUCCESS: 'loginSuccess',
CART_UPDATED: 'cartUpdated',
}
export const EmitterIds = {
SOCKET_MESSAGE: 10001,
DOWNLOAD_FINISHED: 10002,
}
同时注意以下几点:
- 及时注销监听:对于
Emitter,页面销毁或组件不再使用时应主动调用off(),避免重复监听和内存泄漏。 - 避免滥用全局事件:页面间通信优先选择
EventHub,不要所有通知都通过Emitter实现。 - 统一命名规范:事件名称(或
eventId)应按模块划分,避免冲突。 - 减少事件链依赖:不要让一个事件连续触发多个事件,避免形成难以排查的调用链。
- 优先状态管理:对于父子组件或可通过响应式状态解决的问题,优先使用
@State、@Link、@Provide/@Inject等机制,而不是事件总线。
二十一、常见问题(FAQ)
Q1:EventHub 可以跨 UIAbility 吗?
不能。EventHub 的作用域限定在同一个 UIAbility,不同 UIAbility 之间不能直接共享事件。
Q2:Emitter 会自动释放监听吗?
不会。开发者需要在适当的生命周期中调用 off() 注销监听,否则可能导致重复回调或内存泄漏。
Q3:EventHub 和 Emitter 谁性能更高?
两者都基于事件分发机制,在绝大多数业务场景下性能差异可以忽略。真正影响性能的是事件数量、监听器数量以及回调逻辑的复杂度,而不是二者本身。
Q4:可以用 Emitter 完全替代 EventHub 吗?
技术上可以,但不建议。页面内通信使用 EventHub 更符合官方设计,也更容易管理生命周期;Emitter 更适合作为全局事件总线或模块间解耦工具。
二十二、总结
一句话概括:
- EventHub:UIAbility 级别的事件中心,生命周期与
UIAbility一致,适合同一 Ability 内页面之间通信,官方推荐用于页面刷新、状态通知等场景。 - Emitter:应用级事件发送器,基于
@ohos.events.emitter,适合全局模块解耦、SDK 封装、播放器、下载器、WebSocket、推送等跨业务事件分发,需要开发者自行管理监听生命周期。
在大型 HarmonyOS NEXT 项目中,推荐遵循以下原则:
- 组件通信 →
@State、@Prop、@Link - 跨层级通信 →
@Provide/@Inject - 同一 UIAbility 页面通信 →
EventHub - 全局业务模块通信 →
Emitter
更多推荐


所有评论(0)