在 HarmonyOS(鸿蒙)中,emitter 是一个轻量级的事件管理机制,专门用于在同一进程内的不同线程间同一线程内实现事件的发布和订阅。它帮助开发者在多线程环境下实现线程间的消息通信和事件通知,避免了传统的锁机制,从而提升了并发性能和代码的简洁性。


🛠️ 开天辟地 HarmonyOS(鸿蒙)——信息篇:Emitter


✅ 一、emitter 的核心概念

emitter 是基于事件驱动的编程模型,它提供了一个简单的事件发布/订阅机制。开发者可以通过 emitter 在不同的线程或者同一个线程内传递消息,常见应用场景包括:

  • 线程间事件通知:主线程与子线程之间的通信。
  • 同一线程内的事件调度:在事件循环中调度任务。
  • 异步任务的事件通知:任务完成后通知其他任务或组件。

核心操作:

  • 发布事件:向事件系统发布事件。
  • 订阅事件:订阅特定事件并在事件发生时触发回调。
  • 移除订阅:取消对某个事件的订阅。

✅ 二、emitter 适用场景

场景说明
线程间通信通过 emitter 在主线程与子线程之间传递消息
UI 更新通知例如后台任务完成后,使用事件通知 UI 线程进行更新
异步任务处理多个异步任务之间通过事件机制互相通知、协调任务的执行
状态更新推送系统或模块状态变化时,通过事件推送通知相关组件进行处理

✅ 三、基本 API 使用示例(eTS)

🔄 1. 创建和初始化 Emitter

import { Emitter } from '@ohos.event';

const emitter = new Emitter(); // 创建事件发射器

🔄 2. 发布事件(发送事件)

// 发布一个自定义事件
const eventData = { message: "Hello from MainThread", time: Date.now() };
emitter.emit('com.example.UPDATE_UI', eventData);

🔄 3. 订阅事件(接收事件)

// 订阅事件
emitter.on('com.example.UPDATE_UI', (data) => {
  console.log('收到事件:', data);
  // 处理事件,例如更新UI
});

emitter.on() 方法接受事件名和回调函数。回调函数会在事件发布时被调用,传入事件数据。


🔄 4. 取消订阅事件(移除事件监听)

// 取消对某事件的订阅
emitter.off('com.example.UPDATE_UI', (data) => {
  console.log('不再处理事件');
});

使用 emitter.off() 可以移除之前通过 on() 订阅的事件。


✅ 四、异步事件与线程通信

emitter 最常见的应用之一是异步任务的事件通知,尤其是在多线程环境中,不同线程的通信可以通过事件来实现。

🧵 1. 主线程与子线程通信

// 在主线程中创建 emitter
const emitter = new Emitter();

// 子线程中
async function workerThread() {
  // 模拟任务执行
  setTimeout(() => {
    // 任务完成后发布事件
    emitter.emit('com.example.TASK_COMPLETE', { status: 'success' });
  }, 2000);
}

// 订阅事件
emitter.on('com.example.TASK_COMPLETE', (data) => {
  console.log('子线程任务完成:', data);
});

// 启动子线程
workerThread();

在这个示例中,子线程完成任务后通过事件通知主线程,主线程收到事件后执行相应处理。emitter 使得多线程的事件通信变得简单和高效。


✅ 五、事件监听的生命周期

Emitter 提供的事件订阅具有生命周期。即使事件已经被触发,订阅的回调函数依然会被保留,直到你明确取消订阅。回调会在事件被发布时被触发,直到取消订阅或销毁发射器。

🧹 1. 在销毁时清理订阅

如果不再需要某个事件,可以在不需要的时候主动取消订阅,避免内存泄漏。

// 销毁 emitter 时清理订阅
emitter.removeAllListeners();  // 移除所有订阅的事件


🧹 2. 设置最大监听次数

为了防止某个事件被过多次订阅导致内存消耗过大或性能下降,emitter 支持最大监听次数设置。

emitter.setMaxListeners(10); // 设置最多只能有 10 个回调函数


✅ 六、EmitterCommonEventManager 的区别

Emitter 主要用于同一进程内的线程间通信,而 CommonEventManager 则用于跨进程或跨设备的事件通信。两者的作用相似,但应用场景不同:

特性EmitterCommonEventManager
通信范围同一进程内,不同线程间通信跨进程、跨设备的事件通信
性能要求高效,适用于实时性要求较高的通信灵活、可扩展,但有一定延迟
使用场景线程间通信、UI 更新通知系统事件监听、跨应用消息流转
API 复杂度简单,基于事件驱动相对复杂,涉及权限和设备间通信

✅ 七、事件传递数据类型

Emitter 支持传递的事件数据是任意类型,例如:

  • 基本数据类型:string, number, boolean
  • 对象、数组等复合类型
  • 自定义的结构体或类实例

需要注意,不应在事件中传递过大的数据,以免影响性能。


✅ 八、总结

特性描述
高效事件发布/订阅机制避免了线程间同步的复杂度
简洁代码简洁,事件驱动,适合多线程或异步场景
灵活支持自定义事件名,数据类型灵活可扩展
进程内通信适用于同一进程内不同线程之间的轻量级通信

📌 一句话总结:

Emitter 是在同一进程内实现高效、轻量、灵活的线程间通信和事件通知的工具,适用于高并发、低延迟的场景。


如果你需要:

  • 🧪 线程间事件同步的更多案例
  • 🛠️ Emitter 在多线程中的使用技巧
  • 📈 性能优化相关内容