HarmonyOS之Emitter

🧠 一、Emitter 是什么?

Emitter 是 HarmonyOS 提供的一个轻量级事件通信机制 ,用于实现进程内、线程间的异步事件通知与订阅 。它类似于 Node.js 中的 EventEmitter,但为 ArkTS 框架和线程模型进行了专门优化,尤其适合组件解耦、Worker 通信、UI 与后台同步等场景。


⚙️ 二、Emitter 的核心设计原理

1. 事件队列机制

  • Emitter 内部维护了一个 事件队列 ,所有通过 emit 发布的事件都会进入该队列。
  • 队列以 FIFO(先进先出) 的方式异步串行执行事件回调。
  • 通过设置事件优先级(如 LOW / IMMEDIATE)影响事件在队列中的调度顺序。

2. 异步串行调度

  • 所有订阅的回调函数在事件被触发后会逐个执行
  • 如果某个回调耗时过长,可能会阻塞后续事件执行,所以建议回调中避免同步阻塞逻辑。

3. 线程安全设计

  • Emitter 本质上是一种线程间消息传递机制,但其使用方式简洁,无需复杂的线程同步操作。
  • 适用于主线程(UI线程)与 Worker线程(如后台处理)之间的数据通信

🛠️ 三、Emitter 的核心接口详解

方法名 描述 使用示例
on(event, callback) 注册事件监听,持续有效,需手动取消 emitter.on({ eventId: 1 }, cb)
once(event, callback) 注册事件监听,只触发一次后自动移除 emitter.once({ eventId: 1 }, cb)
off(eventId, callback) 注销指定事件和回调函数的订阅 emitter.off(1, cb)
emit(event, data) 发布事件并传递数据 emitter.emit({ eventId: 1 }, { data: xxx })

✅ 接口参数详解:

event: { eventId: string | number, priority?: EventPriority }
  • eventId: 自定义事件标识(可使用字符串或数字)
  • priority: 事件优先级(可选)
data: { data: any }
  • 用户传递的事件数据对象

🧵 四、线程与进程模型下的使用

场景:主线程与 Worker线程 通信

1. Worker 线程发布事件
ts 复制代码
// worker线程
emitter.emit({ eventId: 'background_done' }, { data: '处理完成' });
2. 主线程监听事件
ts 复制代码
emitter.on({ eventId: 'background_done' }, (eventData) => {
  this.result = eventData.data;
  this.updateUI(); // 注意线程安全性
});

💡 线程间通信不需要共享变量或 postMessage,Emitter 自动桥接数据流


📦 五、状态管理与 UI 刷新注意事项

常见问题:UI 未响应事件更新?

原因:
  • 回调中更新的数据变量 未被响应式装饰器(如 @ObservedV2、@State、@Provide)修饰
  • 回调中使用了早绑定的箭头函数,未捕获响应式代理对象。
正确做法:
ts 复制代码
@ObservedV2
class ViewModel {
  @Trace count: number = 0;

  increment() {
    this.count++;
  }
}

// 生命周期绑定回调
aboutToAppear() {
  emitter.on({ eventId: 'count_update' }, () => {
    this.viewModel.increment();
  });
}

🧪 六、常见使用场景

场景 描述
✅ 跨线程通信 主线程与 Worker 通信,替代 postMessage 等复杂机制
✅ 模块解耦 非父子组件间的数据广播,如登录成功后全局通知
✅ 动态事件订阅 某个业务模块需要在运行时动态监听任务完成状态
✅ UI控制逻辑 后台服务状态变化驱动界面展示或提示

📊 七、与 EventHub 的差异总结

特性 Emitter EventHub
使用场景 跨线程通信,模块解耦 组件内通信,UI层事件传递
线程支持 支持主线程 + Worker线程 仅支持 UI线程
事件调度 异步、优先级队列 同步、立即执行
生命周期 手动取消订阅 生命周期自动释放(Stage组件)
响应式集成 需要配合状态装饰器 更紧密集成 UI 生命周期

🧹 八、资源管理与内存泄漏风险

✔️ 正确做法

  • 页面或模块销毁时务必手动调用 off 方法取消订阅
  • 推荐使用 once 替代短期监听,避免忘记取消

示例:

ts 复制代码
private onCallback = (data) => { ... };

aboutToAppear() {
  emitter.on({ eventId: 'task' }, this.onCallback);
}

aboutToDisappear() {
  emitter.off('task', this.onCallback);
}

🔒 九、最佳实践建议

建议 描述
✅ 封装事件工具类 统一事件管理,封装 on/off/emit 逻辑,避免重复代码
✅ 使用枚举管理事件ID 防止硬编码,提升可读性
✅ 避免多个回调监听同一个事件 可能造成重复响应,应通过中间层转发
✅ 日志跟踪事件流程 emit / on 处记录日志便于调试

📁 十、封装工具类示例(建议应用)

ts 复制代码
export enum AppEvent {
  LOGIN_SUCCESS = 'login_success',
  DATA_READY = 'data_ready',
}

export class EmitterUtil {
  private static registry = new Map<string, Function[]>();

  static on(eventId: string, cb: Function) {
    emitter.on({ eventId }, cb);
    const list = this.registry.get(eventId) || [];
    list.push(cb);
    this.registry.set(eventId, list);
  }

  static emit(eventId: string, data: any) {
    emitter.emit({ eventId }, { data });
  }

  static off(eventId: string) {
    const list = this.registry.get(eventId) || [];
    list.forEach(cb => emitter.off(eventId, cb));
    this.registry.delete(eventId);
  }
}

✅ 总结一句话

Emitter 是 HarmonyOS 架构中适用于线程间、模块间通信的高效、非侵入式事件调度器。通过合理封装与状态集成,可实现高内聚、低耦合的通信机制。

相关推荐
光芒Shine12 小时前
【ArkTS-通用事件】
harmonyos
Jackson_Li14 小时前
鸿蒙 Tab 中的 WebView 如何优雅地拦截侧滑返回?
harmonyos
0xCode 小新14 小时前
【鸿蒙心迹】参加ICT大赛对我的影响和帮助
harmonyos
程序员潘Sir15 小时前
鸿蒙应用开发从入门到实战(十八):组件编程思想之代码复用
harmonyos·鸿蒙
安卓开发者2 天前
鸿蒙NEXT跨设备通信:掌握URPC,实现远程程序调用
华为·harmonyos
程序员潘Sir2 天前
鸿蒙应用开发从入门到实战(十七):ArkUI组件List&列表布局
harmonyos·鸿蒙
bst@微胖子2 天前
鸿蒙实现滴滴出行项目之侧边抽屉栏以及权限以及搜索定位功能
android·华为·harmonyos