场景
在App开发的时候,我们通常需要用到一对多的订阅者模式。即订阅者订阅感兴趣的事件,发布者发布特定的事件后,通知到所有该事件的订阅者。那么在鸿蒙中订阅者模式通过哪些类来实现呢?
概述
鸿蒙应用中的应用事件按照 通信方式分成进程间通信和线程间通信。进程间通信负责系统级别的事件发布、订阅和取消订阅,其中包含了开发者的创建自定义的公共事件,实现应用间的通信;而线程间通信提供了App应用内的事件订阅、取消订阅以及发送事件。
应用事件-进程间通信(公共事件CES)
公共事件简介
CES(Common Event Service,公共事件服务)为应用程序提供订阅、发布、退订公共事件的能力。
公共事件从系统角度可分为:系统公共事件和自定义公共事件。
- 系统公共事件:CES内部定义的公共事件,当前仅支持系统应用和系统服务发布,例如HAP安装,更新,卸载等公共事件。目前支持的系统公共事件请参见系统公共事件列表。
- 自定义公共事件:应用定义的公共事件,可用于实现跨进程的事件通信能力。
公共事件按发送方式可分为:无序公共事件、有序公共事件和粘性公共事件。
- 无序公共事件:CES在转发公共事件时,不考虑订阅者是否接收到该事件,也不保证订阅者接收到该事件的顺序与其订阅顺序一致。
- 有序公共事件:CES在转发公共事件时,根据订阅者设置的优先级等级,优先将公共事件发送给优先级较高的订阅者,等待其成功接收该公共事件之后再将事件发送给优先级较低的订阅者。如果有多个订阅者具有相同的优先级,则他们将随机接收到公共事件。
- 粘性公共事件:能够让订阅者收到在订阅前已经发送的公共事件就是粘性公共事件。普通的公共事件只能在订阅后发送才能收到,而粘性公共事件的特殊性就是可以先发送后订阅,同时也支持先订阅后发送。发送粘性事件必须是系统应用或系统服务,粘性事件发送后会一直存在系统中,且发送者需要申请ohos.permission.COMMONEVENT_STICKY权限。(普通应用不会使用该事件)
每个应用都可以按需订阅公共事件,订阅成功,当公共事件发布时,系统会将其发送给对应的应用。这些公共事件可能来自系统、其他应用和应用自身。
公共事件示意图
公共事件订阅
事件订阅有两个步骤:
createSubscriber
创建订阅者对象subscribe
定义订阅动作(事件发生后,执行的回调)
import Base from '@ohos.base';
import commonEventManager from '@ohos.commonEventManager';
import promptAction from '@ohos.promptAction';
const TAG: string = 'ProcessModel';
// 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作
let subscriber: commonEventManager.CommonEventSubscriber | null = null;
// 订阅者信息,其中的event字段需要替换为实际的事件名称。
let subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
events: ['event'], // 订阅灭屏公共事件
};
// 创建订阅者回调
commonEventManager.createSubscriber(subscribeInfo, (err: Base.BusinessError, data: commonEventManager.CommonEventSubscriber) => {
if (err) {
console.error(`Failed to create subscriber. Code is ${err.code}, message is ${err.message}`);
return;
}
console.info('Succeeded in creating subscriber.');
subscriber = data;
// 订阅公共事件回调
...
})
// 订阅公共事件回调
if (this.subscriber !== null) {
commonEventManager.subscribe(subscriber, (err: Base.BusinessError, data: commonEventManager.CommonEventData) => {
if (err) {
console.error(`Failed to subscribe common event. Code is ${err.code}, message is ${err.message}`);
return;
}
})
} else {
console.error(`Need create subscriber`);
}
公共事件取消订阅
取消订阅直接执行unsubscribe
方法即可。
import Base from '@ohos.base';
import commonEventManager from '@ohos.commonEventManager';
import promptAction from '@ohos.promptAction';
const TAG: string = 'ProcessModel';
// subscriber为订阅事件时创建的订阅者对象
if (this.subscriber !== null) {
commonEventManager.unsubscribe(this.subscriber, (err: Base.BusinessError) => {
if (err) {
console.error(TAG, `UnsubscribeCallBack err = ${JSON.stringify(err)}`);
} else {
promptAction.showToast({
message: $r('app.string.unsubscribe_success_toast')
});
console.info(TAG, `Unsubscribe success`);
this.subscriber = null;
}
})
} else {
promptAction.showToast({
message: $r('app.string.unsubscribe_failed_toast')
});
}
公共事件发布
发布自定义事件调用publish
实现
import Base from '@ohos.base';
import commonEventManager from '@ohos.commonEventManager';
const TAG: string = 'ProcessModel';
// 发布公共事件,其中的event字段需要替换为实际的事件名称。
commonEventManager.publish('event', (err: Base.BusinessError) => {
if (err) {
console.info(`PublishCallBack err = ${JSON.stringify(err)}`);
} else {
...
console.info(`Publish success`);
}
});
应用事件-线程间通信(Emitter)
Emitter主要提供线程间发送和处理事件的能力,包括对持续订阅事件或单次订阅事件的处理、取消订阅事件、发送事件到事件队列等。
订阅事件
通过on
方法实现订阅
import emitter from '@ohos.events.emitter';
import promptAction from '@ohos.promptAction';
import Logger from '../utils/Logger';
const TAG: string = 'ThreadModel';
// 定义一个eventId为1的事件
let event: emitter.InnerEvent = {
eventId: 1
};
// 收到eventId为1的事件后执行该回调
let callback = (eventData: emitter.EventData): void => {
promptAction.showToast({
message: JSON.stringify(eventData.data?.content)
});
Logger.info(TAG, 'event callback:' + JSON.stringify(eventData.data?.content));
};
// 订阅eventId为1的事件
emitter.on(event, callback);
promptAction.showToast({
message: $r('app.string.emitter_subscribe_success_toast')
});
发送事件
通过emit
方法发送事件
import emitter from '@ohos.events.emitter';
// 定义一个eventId为1的事件,事件优先级为Low
let event: emitter.InnerEvent = {
eventId: 1,
priority: emitter.EventPriority.LOW
};
let eventData: emitter.EventData = {
data: {
content: 'c',
id: 1,
isEmpty: false
}
};
// 发送eventId为1的事件,事件内容为eventData
emitter.emit(event, eventData);
Emitter其他方法
once
单次订阅指定事件,并在接收到该事件并执行完相应的回调函数后,自动取消订阅。off
取消针对该事件ID的订阅,传入可选参数callback,并且该callback已经通过on或者once接口订阅,则取消该订阅;否则,不做任何处理。
总结
应用间通讯使用CES实现,App应用内的事件订阅使用Emitter实现。