一、前言

很多刚学习 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,
}

同时注意以下几点:

  1. 及时注销监听:对于 Emitter,页面销毁或组件不再使用时应主动调用 off(),避免重复监听和内存泄漏。
  2. 避免滥用全局事件:页面间通信优先选择 EventHub,不要所有通知都通过 Emitter 实现。
  3. 统一命名规范:事件名称(或 eventId)应按模块划分,避免冲突。
  4. 减少事件链依赖:不要让一个事件连续触发多个事件,避免形成难以排查的调用链。
  5. 优先状态管理:对于父子组件或可通过响应式状态解决的问题,优先使用 @State@Link@Provide/@Inject 等机制,而不是事件总线。

二十一、常见问题(FAQ)

Q1:EventHub 可以跨 UIAbility 吗?

不能。EventHub 的作用域限定在同一个 UIAbility,不同 UIAbility 之间不能直接共享事件。

Q2:Emitter 会自动释放监听吗?

不会。开发者需要在适当的生命周期中调用 off() 注销监听,否则可能导致重复回调或内存泄漏。

Q3:EventHub 和 Emitter 谁性能更高?

两者都基于事件分发机制,在绝大多数业务场景下性能差异可以忽略。真正影响性能的是事件数量、监听器数量以及回调逻辑的复杂度,而不是二者本身。

Q4:可以用 Emitter 完全替代 EventHub 吗?

技术上可以,但不建议。页面内通信使用 EventHub 更符合官方设计,也更容易管理生命周期;Emitter 更适合作为全局事件总线或模块间解耦工具。


二十二、总结

一句话概括:

  • EventHubUIAbility 级别的事件中心,生命周期与 UIAbility 一致,适合同一 Ability 内页面之间通信,官方推荐用于页面刷新、状态通知等场景。
  • Emitter应用级事件发送器,基于 @ohos.events.emitter,适合全局模块解耦、SDK 封装、播放器、下载器、WebSocket、推送等跨业务事件分发,需要开发者自行管理监听生命周期。

在大型 HarmonyOS NEXT 项目中,推荐遵循以下原则:

  • 组件通信@State@Prop@Link
  • 跨层级通信@Provide / @Inject
  • 同一 UIAbility 页面通信EventHub
  • 全局业务模块通信Emitter
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐