【HarmonyOS NEXT】EventHub和Emitter的使用场景与区别

一、EventHub是什么?

移动应用开发的同学应该比较了解EventHub,类似于EventBus。标准的事件广播通知,订阅,取消订阅的处理。EventHub模块提供了事件中心,提供订阅、取消订阅、触发事件的能力。

类似的框架工具有很多,例如MQTT。使用起来也超级简单,从介绍上就能大体了解使用方式,见名知意的一种快捷工具。通过一个事件ID即TAG作为唯一的key,进行事件广播通知和订阅。

在ArkUI框架中,EventHub通过单例对象的形式提供,因为放在上下文里。所以每个UIAbility对应一个EventHub。不同的UIAbility的EventHub是不同步的。

从上下文获取EventHub有两种方式:

  1. 在UIAbility中直接通过context获取:
typescript 复制代码
import { UIAbility, Context, Want, AbilityConstant } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 获取eventHub
    let eventhub = this.context.eventHub;
    });
  }
}
  1. 在page界面或者组件中,通过UIcontext强转为UIAbilityContext获取:
typescript 复制代码
let context = getContext(this) as common.UIAbilityContext;
let eventhub = context.eventHub;

获得到EventHub单例对象后,就可以调用emit发送事件,on监听事件,off取消监听事件。进行事件广播的使用。

typescript 复制代码
  // TAG作为事件的id为字符串类型
  private EVENT_TAG: string = "TEST";
  
  /**
   * EventHub事件回调
   */
  callbackByEventHub = (content: string)=>{
    promptAction.showToast({
      message: JSON.stringify(content)
    });
  }
  
this.eventHub?.on(this.EVENT_TAG, this.callbackByEventHub); this.eventHub?.off(this.EVENT_TAG, this.callbackByEventHub);
this.eventHub?.off(this.EVENT_TAG);// 第二个参数不传,则代表EVENT_TAG下的所有注册回调都清空

详情参见官网,示例DEMO参见最后章节:
UIAbility组件与UI的数据同步
EventHub API文档

二、Emitter是什么?

类似于EventHub的使用,只是内部封装了事件队列和分发的机制。多了事件id和优先级的概念。并且Emitter也可以在不同线程内调用。

Emitter区别于上文中的EventHub的事件ID,定义了一层对象进行约束。除了事件id,还需要设置事件级别。

typescript 复制代码
  private event: emitter.InnerEvent = {
    eventId: this.eventId,
    priority: emitter.EventPriority.LOW   // 定义一个eventId为1的事件,事件优先级为Low
  };

事件级别分为以下几种类型:

和EventHub不同的是,事件广播的内容,也进行了约束。 发送事件时传递的数据,支持数据类型包括Array、ArrayBuffer、Boolean、DataView、Date、Error、Map、Number、Object、Primitive(除了symbol)、RegExp、Set、String、TypedArray,数据大小最大为16M。

data是key val形式的对象,可以自己定义里面的key和val。

typescript 复制代码
    let eventData: emitter.EventData = {
      data: {
        content: '测试数据',
        id: 1,
        isEmpty: false
      }
    };

事件的广播发送,订阅和取消订阅与EventHub区别不大。只是多了once一次性监听而已。

typescript 复制代码
  private callback = (eventData: emitter.EventData): void => {

  };

    emitter.emit(this.event, eventData);
    emitter.once(this.event, this.callback)
    emitter.off(this.event.eventId, this.callback);

详情参见官网,示例DEMO参见最后章节:
使用Emitter进行线程间通信
EventHub API文档

三、EventHub和Emitter的使用场景与区别

  1. EventHub是线程内使用的时间广播工具,Emitter是线程间通信使用的工具
  2. EventHub的使用更简单,属于轻量级的广播工具,主要用于UIAbility和page之间,page和组件之间,组件和组件之间,UI和VM之间的通信,传递的数据内容形式多变且方便(...args: Object[])。Emitter属于重量级的广播工具,封装了优先级和队列的逻辑。传递的数据内容,必须有包裹成进行约束(emitter.EventData)
  3. Emitter监听设置,在on基础上,额外提供了once一次性监听的API。触发之后不需要再手动off取消监听。EventHub则没有。

源码DEMO解析:

typescript 复制代码
import { emitter } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';

@Entry
@Component
struct EventHubAndEmitterTestPage {

  // --------------- EventHub
  private context = getContext(this) as common.UIAbilityContext;
  private eventHub: common.EventHub | null = null;
  private EVENT_TAG: string = "TEST";

  private emitByEventHub(){
    this.eventHub = this.context.eventHub;
    this.eventHub.emit(this.EVENT_TAG, "测试数据EventHub");
  }

  /**
   * EventHub事件回调
   */
  callbackByEventHub = (content: string)=>{
    promptAction.showToast({
      message: JSON.stringify(content)
    });
  }

  private registerByEventHub = ()=>{
    this.eventHub?.on(this.EVENT_TAG, this.callbackByEventHub);
  }

  private unRegisterByEventHub = ()=>{
    this.eventHub?.off(this.EVENT_TAG, this.callbackByEventHub);
  }

  // --------------- Emitter
  private eventId: number = 1;
  private event: emitter.InnerEvent = {
    eventId: this.eventId,
    priority: emitter.EventPriority.LOW   // 定义一个eventId为1的事件,事件优先级为Low
  };

  private emitByEmitter(){
    let eventData: emitter.EventData = {
      data: {
        content: '测试数据',
        id: 1,
        isEmpty: false
      }
    };

    // 发送eventId为1的事件,事件内容为eventData
    emitter.emit(this.event, eventData);
  }

  private callback = (eventData: emitter.EventData): void => {
    promptAction.showToast({
      message: JSON.stringify(eventData)
    });
  };

  private registerByEmitter(){
    emitter.on(this.event, this.callback);
    // 监听触发后,自动消除监听。不需要手动off
    emitter.once(this.event, this.callback)
  }

  private unRegisterByEmitter(){
    emitter.off(this.event.eventId, this.callback);
  }

  // ---------------点击事件处理

  onEmitEvent = ()=>{
    this.emitByEmitter();
    this.emitByEventHub();
  }

  onRegisterEvent = ()=>{
    this.registerByEmitter();
    this.registerByEventHub();
  }

  onUnRegisterEvent = ()=>{
    this.unRegisterByEmitter();
    this.unRegisterByEventHub();

  }
  
  /**
   * 统一样式封装
   */
  @Styles ButtonStyle(){
    .width(px2vp(350))
    .height(px2vp(200))
    .margin({ top: px2vp(66) })
  }

  build() {
    Column(){
      Button("发送事件")
        .ButtonStyle()
        .onClick(this.onEmitEvent)

      Button("监听事件")
        .ButtonStyle()
        .onClick(this.onRegisterEvent)

      Button("取消事件")
        .ButtonStyle()
        .onClick(this.onUnRegisterEvent)

    }.size({
      width: "100%",
      height: "100%"
    })
  }
}
相关推荐
康康这名还挺多1 小时前
鸿蒙HarmonyOS list优化一: list 结合 lazyforeach用法
数据结构·list·harmonyos·lazyforeach
晚秋大魔王4 小时前
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——nettle库
linux·开源·harmonyos
python算法(魔法师版)8 小时前
.NET 在鸿蒙系统上的适配现状
华为od·华为·华为云·.net·wpf·harmonyos
bestadc9 小时前
鸿蒙 UIAbility组件与UI的数据同步和窗口关闭
harmonyos
枫叶丹410 小时前
【HarmonyOS Next之旅】DevEco Studio使用指南(二十二)
华为·harmonyos·deveco studio·harmonyos next
ax一号街阿楠12 小时前
华为FAT AP配置 真机
网络·华为·智能路由器
吗喽对你问好12 小时前
华为5.7机考第一题充电桩问题Java代码实现
java·华为·排序
乱世刀疤14 小时前
深度 |国产操作系统“破茧而出”:鸿蒙电脑填补自主生态空白
华为·harmonyos
博睿谷IT99_19 小时前
华为HCIP-AI认证考试版本更新通知
人工智能·华为
连续讨伐19 小时前
ensp的华为小实验
华为