鸿蒙NEXT实战:使用公共事件实现跨进程通信
在鸿蒙应用开发中,巧妙使用公共事件机制,能让跨进程通信变得轻松高效。
在鸿蒙应用开发中,进程间通信(IPC)是一个常见需求。HarmonyOS NEXT 提供了多种IPC机制,其中公共事件(Common Event)因其简单易用且支持一对多通信模式,成为许多场景下的理想选择。
公共事件机制概述
公共事件是HarmonyOS中的一种发布-订阅模式的通信机制,适用于跨进程、跨应用的事件通知场景。它基于消息中心机制,允许一个进程发布事件,多个进程订阅并接收该事件。
公共事件的特点:
跨进程通信:能够在不同进程间传递事件
一对多通信:一个事件可以被多个订阅者接收
异步执行:事件发布后立即返回,不会阻塞发布者线程
松耦合:发布者和订阅者不需要知道彼此的存在
公共事件的工作原理
公共事件机制涉及三个核心角色:
发布者:负责创建并发布公共事件
订阅者:注册对特定事件的兴趣,并定义回调处理函数
公共事件管理器:系统组件,负责管理事件的分发
当发布者发布一个事件时,公共事件管理器会根据事件的类型和权限,将事件传递给所有匹配的订阅者。
实战:使用公共事件实现跨进程通信
下面通过一个完整示例,演示如何在鸿蒙NEXT中使用公共事件进行跨进程通信。
1. 创建事件订阅者
首先,我们需要在接收方进程中创建事件订阅者:
typescript
import commonEventManager from '@ohos.commonEventManager'; import Base from '@ohos.base';// 订阅公共事件 function subscribeCommonEvent() {const subscribeInfo = {events: ["com.example.demo.MY_EVENT"] // 要订阅的事件类型};// 创建订阅者commonEventManager.createSubscriber(subscribeInfo, (err: Base.BusinessError, subscriber: 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.');// 订阅事件if (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;}console.info('Subscribe success, received event data:' + JSON.stringify(data));// 处理接收到的事件数据handleReceivedEvent(data);});} else {console.error(`Need create subscriber`);}}); }// 处理接收到的事件 function handleReceivedEvent(eventData: commonEventManager.CommonEventData) {const receivedData = eventData.data;const code = eventData.code;console.info(`Received event, code: ${code}, data: ${JSON.stringify(receivedData)}`);// 根据事件数据更新UI或执行其他操作// ... }
2. 发布公共事件
在发送方进程中,创建并发布公共事件:
typescript
import commonEventManager from '@ohos.commonEventManager'; import Base from '@ohos.base';// 发布公共事件 function publishCommonEvent() {const options: commonEventManager.CommonEventPublishData = {code: 1, // 事件代码data: "This is event data", // 事件数据bundleName: "com.example.publisher" // 可选:发布者包名};// 发布公共事件commonEventManager.publish("com.example.demo.MY_EVENT", options, (err: Base.BusinessError) => {if (err) {console.error('[CommonEvent] PublishCallBack err=' + JSON.stringify(err));} else {console.info('[CommonEvent] Publish success');}}); }// 发布带复杂数据的事件 function publishComplexEvent() {const complexData = {message: "Hello from another process!",timestamp: new Date().getTime(),count: 42};const options: commonEventManager.CommonEventPublishData = {code: 1001,data: JSON.stringify(complexData) // 复杂数据需要序列化};commonEventManager.publish("com.example.demo.COMPLEX_EVENT", options, (err: Base.BusinessError) => {if (err) {console.error('Failed to publish complex event: ' + JSON.stringify(err));} else {console.info('Complex event published successfully');}}); }
3. 在Ability中集成公共事件
在EntryAbility中订阅公共事件:
typescript
import UIAbility from '@ohos.app.ability.UIAbility'; import commonEventManager from '@ohos.commonEventManager'; import window from '@ohos.window'; import Base from '@ohos.base';export default class EntryAbility extends UIAbility {private subscriber: commonEventManager.CommonEventSubscriber | null = null;onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {console.info('EntryAbility onCreate');this.subscribeToEvents();}private subscribeToEvents(): void {const subscribeInfo = {events: ["com.example.demo.MY_EVENT"]};commonEventManager.createSubscriber(subscribeInfo, (err: Base.BusinessError, subscriber: commonEventManager.CommonEventSubscriber) => {if (err) {console.error(`Failed to create subscriber in Ability. Code is ${err.code}, message is ${err.message}`);return;}this.subscriber = subscriber;console.info('Succeeded in creating subscriber in Ability.');if (this.subscriber !== null) {commonEventManager.subscribe(this.subscriber, (err: Base.BusinessError, data: commonEventManager.CommonEventData) => {if (err) {console.error(`Failed to subscribe common event in Ability. Code is ${err.code}, message is ${err.message}`);return;}console.info('Ability received event data: ' + JSON.stringify(data));});}});}onDestroy(): void {// 取消订阅if (this.subscriber !== null) {commonEventManager.unsubscribe(this.subscriber, (err: Base.BusinessError) => {if (err) {console.error(`Failed to unsubscribe common event. Code is ${err.code}, message is ${err.message}`);return;}console.info('Succeeded in unsubscribing common event.');});}super.onDestroy();} }
4. 在UI页面中发布事件
在SubPage.ets页面中发布事件:
typescript
@Entry @Component struct SubPage {@State message: string = 'Hello World';build() {Column() {Text(this.message).fontSize(20).margin(10)Button('发布简单事件').onClick(() => {this.publishSimpleEvent();}).margin(10)Button('发布复杂事件').onClick(() => {this.publishComplexEvent();}).margin(10)}.width('100%').height('100%')}private publishSimpleEvent() {let options: commonEventManager.CommonEventPublishData = {code: 1,data: "initial data",};commonEventManager.publish("selfPublishEvent", options, (err: Base.BusinessError) => {if (err) {console.error('[CommonEvent] PublishCallBack err=' + JSON.stringify(err));} else {console.info('[CommonEvent] Publish success');this.message = '事件发布成功!';}});}private publishComplexEvent() {const eventData = {action: 'USER_ACTION',userId: '12345',screen: 'MainPage',timestamp: new Date().toISOString()};let options: commonEventManager.CommonEventPublishData = {code: 200,data: JSON.stringify(eventData),};commonEventManager.publish("com.example.demo.USER_ACTION_EVENT", options, (err: Base.BusinessError) => {if (err) {console.error('Failed to publish user action event: ' + JSON.stringify(err));this.message = '事件发布失败';} else {console.info('User action event published successfully');this.message = '用户动作事件已发布';}});} }
公共事件的进阶用法
1. 使用有序公共事件
有序公共事件允许订阅者按照优先级处理事件,并可以终止事件的传播:
typescript
// 发布有序公共事件 function publishOrderedEvent() {const options: commonEventManager.CommonEventPublishData = {code: 1,data: "Ordered event data",isOrdered: true // 设置为有序事件};commonEventManager.publish("com.example.demo.ORDERED_EVENT", options, (err: Base.BusinessError) => {if (err) {console.error('Failed to publish ordered event: ' + JSON.stringify(err));} else {console.info('Ordered event published successfully');}}); }
2. 使用粘性公共事件
粘性事件会在发布后保留在系统中,新的订阅者仍然可以收到之前发布的事件:
typescript
// 发布粘性公共事件 function publishStickyEvent() {const options: commonEventManager.CommonEventPublishData = {code: 1,data: "Sticky event data",isSticky: true // 设置为粘性事件};commonEventManager.publish("com.example.demo.STICKY_EVENT", options, (err: Base.BusinessError) => {if (err) {console.error('Failed to publish sticky event: ' + JSON.stringify(err));} else {console.info('Sticky event published successfully');}}); }
3. 订阅系统公共事件
除了自定义事件,还可以订阅系统预定义的公共事件:
typescript
// 订阅系统事件:屏幕点亮 function subscribeSystemEvent() {const subscribeInfo = {events: [commonEvent.SCREEN_ON] // 系统预定义事件};commonEventManager.createSubscriber(subscribeInfo, (err: Base.BusinessError, subscriber: commonEventManager.CommonEventSubscriber) => {if (err) {console.error(`Failed to create system event subscriber. Code is ${err.code}, message is ${err.message}`);return;}if (subscriber !== null) {commonEventManager.subscribe(subscriber, (err: Base.BusinessError, data: commonEventManager.CommonEventData) => {if (err) {console.error(`Failed to subscribe system event. Code is ${err.code}, message is ${err.message}`);return;}console.info('Screen turned on');// 处理屏幕点亮事件});}}); }
开发注意事项
权限管理:某些系统事件需要相应的权限才能订阅,确保在module.json5中声明所需权限。
性能考虑:避免在事件回调中执行耗时操作,以免影响系统性能。
内存管理:及时取消不再需要的事件订阅,防止内存泄漏。
数据大小:事件数据不宜过大,建议控制在KB级别。
错误处理:始终处理发布和订阅操作的可能错误,提高应用稳定性。
与其他通信方式的对比
虽然公共事件功能强大,但鸿蒙NEXT还提供了其他进程间通信方式,可根据具体场景选择:
Emitter:用于同一进程内的线程间通信
Binder:用于跨进程通信,支持同步和异步调用
共享内存:通过共享内存区域实现高效数据传输
与这些机制相比,公共事件更适合一对多、异步、松耦合的通信场景。
总结
公共事件机制是鸿蒙NEXT中实现跨进程通信的强大工具,通过简单的发布-订阅模式,可以轻松实现进程间的解耦通信。本文介绍了公共事件的基本用法和进阶特性,希望能帮助你在实际开发中更好地利用这一机制。
掌握公共事件的使用,将为构建复杂、高效的鸿蒙应用奠定坚实基础。