目录

如何使用EventHub替代EventBus实现事件通信

问题现象

在HarmonyOS应用开发中,当需要进行组件间或模块间的事件发布与订阅以实现解耦通信时,部分三方库(如EventBus)可能未提供HarmonyOS适配版本。开发者需要寻找系统提供的替代方案来实现基于发布-订阅模式的事件通信机制。

背景知识

EventHub是HarmonyOS系统提供的基于发布-订阅模式实现的事件通信机制。通过事件名,实现了发送方和订阅方之间的解耦,支持不同业务模块间的高效数据传递和状态同步。更多参考请参见EventHub。

解决方案

使用系统提供的EventHub替代EventBus。通过UIAbilityContext获取EventHub实例,使用on方法订阅事件,使用emit方法发送事件,并在Ability销毁时调用off方法取消订阅以避免内存泄漏。在ArkUI组件中,可通过getContext(this)获取UIAbilityContext,从而在组件侧使用EventHub进行事件通信。

以下示例在EntryAbility中演示事件的订阅、发送与取消订阅,并提取统一的错误处理函数以减少代码重复:
import { UIAbility } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

export default class EntryAbility extends UIAbility {
  value: number = 12;

  // 统一错误处理函数
  handleEventError(e: BusinessError) {
    let code: number = e.code;
    let msg: string = e.message;
    console.error(`EventHub error, code: ${code}, msg: ${msg}`);
  }

  onCreate() {
    try {
      // 支持使用匿名函数订阅事件
      this.context.eventHub.on('myEvent', () => {
        console.info(`anonymous eventFunc is called, value: ${this.value}`);
      });
    } catch (e) {
      this.handleEventError(e as BusinessError);
    }
  }

  onForeground() {
    try {
      // 结果:
      // anonymouseventFunciscalled, value: 12
      this.context.eventHub.emit('myEvent');
    } catch (e) {
      this.handleEventError(e as BusinessError);
    }
  }

  onDestroy() {
    // 销毁时取消事件订阅,避免内存泄漏
    try {
      this.context.eventHub.off('myEvent');
    } catch (e) {
      this.handleEventError(e as BusinessError);
    }
  }
}
以下示例在ArkUI组件中通过getContext(this)获取UIAbilityContext,演示组件侧的事件订阅与发送:
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  value: number = 10;

  aboutToAppear() {
    // 在组件中通过getContext(this)获取UIAbilityContext
    let context = getContext(this) as common.UIAbilityContext;
    try {
      context.eventHub.on('componentEvent', () => {
        console.info(`componentEvent is called, value: ${this.value}`);
      });
    } catch (e) {
      let code: number = (e as BusinessError).code;
      let msg: string = (e as BusinessError).message;
      console.error(`subscribe componentEvent failed, code: ${code}, msg: ${msg}`);
    }
  }

  aboutToDisappear() {
    // 组件销毁时取消订阅,避免内存泄漏
    let context = getContext(this) as common.UIAbilityContext;
    try {
      context.eventHub.off('componentEvent');
    } catch (e) {
      let code: number = (e as BusinessError).code;
      let msg: string = (e as BusinessError).message;
      console.error(`unsubscribe componentEvent failed, code: ${code}, msg: ${msg}`);
    }
  }

  build() {
    Column() {
      Button('发送事件')
        .onClick(() => {
          let context = getContext(this) as common.UIAbilityContext;
          try {
            context.eventHub.emit('componentEvent');
          } catch (e) {
            let code: number = (e as BusinessError).code;
            let msg: string = (e as BusinessError).message;
            console.error(`emit componentEvent failed, code: ${code}, msg: ${msg}`);
          }
        })
    }
  }
}