HarmonyOS事件订阅与通知:后台事件处理
本文将深入探讨HarmonyOS 5(API 12)中的事件订阅与通知机制,重点讲解如何在后台处理事件,实现应用的实时响应和跨设备协同。内容涵盖核心API、实现步骤、实战示例及性能优化建议。
1. 事件订阅与通知机制概述
HarmonyOS的事件系统采用发布-订阅模式,允许应用在后台监听和处理系统事件、自定义事件及跨设备事件。其核心优势包括:
- 跨进程通信:支持应用间事件传递,解耦组件依赖。
- 后台唤醒:即使应用处于后台,也能通过事件唤醒并执行任务。
- 统一事件管理:提供通用的事件订阅、发布和取消订阅接口。
- 跨设备同步:结合分布式能力,实现事件在多个设备间同步触发。
1.1 核心API介绍
HarmonyOS 5的事件处理主要依赖以下模块:
@ohos.commonEventManager
:系统通用事件管理,如屏幕亮灭、网络变化等。@ohos.remoteNotification
:远程通知管理,用于处理推送事件。@ohos.distributedDeviceManager
:分布式设备管理,支持跨设备事件订阅。BackgroundTaskManager
:后台任务管理,确保事件处理在后台可持续运行。
2. 通用事件订阅与处理
通用事件(CommonEvent)是系统预定义的事件(如时间变化、网络状态变化),应用可订阅这些事件并在后台响应。
2.1 订阅系统事件
以下示例演示如何订阅屏幕亮灭事件,并在后台处理:
import commonEventManager from '@ohos.commonEventManager';
import commonEvent from '@ohos.commonEvent';
import { BusinessError } from '@ohos.base';@Entry
@Component
struct CommonEventDemo {// 订阅者对象private subscriber: commonEventManager.CommonEventSubscriber | null = null;// 订阅参数private subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {events: [commonEvent.SCREEN_OFF, commonEvent.SCREEN_ON] // 订阅事件列表};// 组件初始化时订阅事件async aboutToAppear() {await this.subscribeCommonEvent();}// 订阅事件private async subscribeCommonEvent() {try {// 创建订阅者this.subscriber = await commonEventManager.createSubscriber(this.subscribeInfo);// 注册事件回调this.subscriber.on('receive', (event: commonEventManager.CommonEventData) => {console.log(`收到事件: ${event.event}`);this.handleScreenEvent(event.event);});console.log('通用事件订阅成功');} catch (error) {console.error(`订阅失败: ${(error as BusinessError).message}`);}}// 处理屏幕事件private handleScreenEvent(event: string) {// 后台处理逻辑:即使应用在后台也能执行switch (event) {case commonEvent.SCREEN_ON:// 屏幕点亮时处理this.onScreenOn();break;case commonEvent.SCREEN_OFF:// 屏幕熄灭时处理this.onScreenOff();break;}}private onScreenOn() {// 示例:屏幕亮起时刷新数据console.log('屏幕已点亮,开始后台数据同步...');this.refreshData();}private onScreenOff() {// 示例:屏幕熄灭时释放资源console.log('屏幕已熄灭,释放非必要资源...');this.releaseResources();}// 后台数据刷新private async refreshData() {// 实际项目中可从这里发起网络请求或更新本地数据console.log('执行后台数据刷新任务');}// 资源释放private releaseResources() {console.log('释放音频、传感器等资源');}// 取消订阅private async unsubscribeCommonEvent() {if (this.subscriber) {try {await commonEventManager.unsubscribe(this.subscriber);console.log('取消订阅成功');} catch (error) {console.error(`取消订阅失败: ${(error as BusinessError).message}`);}}}// 组件销毁时取消订阅aboutToDisappear() {this.unsubscribeCommonEvent();}build() {Column() {Text('通用事件订阅示例').fontSize(20).margin(10)Text('尝试开关屏幕查看控制台输出').fontSize(16).margin(10)}.width('100%').height('100%')}
}
2.2 支持订阅的常见系统事件
事件类型 | 常量名 | 触发条件 | 后台处理能力 |
---|---|---|---|
屏幕点亮 | SCREEN_ON | 屏幕从熄灭变亮 | 支持 |
屏幕熄灭 | SCREEN_OFF | 屏幕熄灭 | 支持 |
充电状态 | BATTERY_CHARGING | 开始充电 | 支持 |
充电完成 | BATTERY_FULL | 电池充满 | 支持 |
网络变化 | NETWORK_AVAILABLE | 网络连接状态变化 | 支持 |
时间变化 | TIME_TICK | 系统时间每分钟变化 | 支持 |
包安装 | PACKAGE_ADDED | 新应用安装 | 支持 |
包移除 | PACKAGE_REMOVED | 应用被卸载 | 支持 |
3. 自定义事件与跨设备事件
除了系统事件,应用还可以定义和发布自己的事件,并支持跨设备同步。
3.1 自定义事件发布与订阅
import commonEventManager from '@ohos.commonEventManager';
import commonEvent from '@ohos.commonEvent';
import { BusinessError } from '@ohos.base';// 定义自定义事件
const CUSTOM_EVENTS = {USER_LOGIN: 'com.example.APP.USER_LOGIN',DATA_UPDATED: 'com.example.APP.DATA_UPDATED'
};@Entry
@Component
struct CustomEventDemo {private subscriber: commonEventManager.CommonEventSubscriber | null = null;// 订阅自定义事件private async subscribeCustomEvents() {const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {events: [CUSTOM_EVENTS.USER_LOGIN, CUSTOM_EVENTS.DATA_UPDATED]};try {this.subscriber = await commonEventManager.createSubscriber(subscribeInfo);this.subscriber.on('receive', (event: commonEventManager.CommonEventData]) => {console.log(`收到自定义事件: ${event.event}`);console.log(`事件数据: ${JSON.stringify(event.parameters)}`);// 根据事件类型处理switch (event.event) {case CUSTOM_EVENTS.USER_LOGIN:this.handleUserLogin(event.parameters);break;case CUSTOM_EVENTS.DATA_UPDATED:this.handleDataUpdated(event.parameters);break;}});console.log('自定义事件订阅成功');} catch (error) {console.error(`自定义事件订阅失败: ${(error as BusinessError).message}`);}}// 发布自定义事件private async publishCustomEvent(event: string, params: Record<string, Object>) {try {await commonEventManager.publish(event, {parameters: params});console.log(`事件发布成功: ${event}`);} catch (error) {console.error(`事件发布失败: ${(error as BusinessError).message}`);}}// 处理用户登录事件private handleUserLogin(params: Record<string, Object>) {const username = params['username'] || '未知用户';console.log(`用户登录: ${username}`);// 执行后台任务,如同步用户数据}// 处理数据更新事件private handleDataUpdated(params: Record<string, Object>) {const dataType = params['dataType'] || '未知类型';console.log(`数据已更新: ${dataType}`);// 执行后台任务,如刷新缓存}build() {Column() {Button('发布用户登录事件').onClick(() => {this.publishCustomEvent(CUSTOM_EVENTS.USER_LOGIN, {username: '张三',userId: '12345',timestamp: Date.now()});}).margin(10).width('80%')Button('发布数据更新事件').onClick(() => {this.publishCustomEvent(CUSTOM_EVENTS.DATA_UPDATED, {dataType: '用户配置',updateCount: 5,timestamp: Date.now()});}).margin(10).width('80%')}.width('100%').height('100%').onAppear(() => {this.subscribeCustomEvents();}).onDisappear(() => {if (this.subscriber) {commonEventManager.unsubscribe(this.subscriber);}})}
}
3.2 跨设备事件同步
HarmonyOS的分布式能力允许事件在多个设备间同步触发。
import deviceManager from '@ohos.distributedDeviceManager';
import commonEventManager from '@ohos.commonEventManager';
import { BusinessError } from '@ohos.base';@Entry
@Component
struct DistributedEventDemo {// 获取可信设备列表private getTrustedDevices(): string[] {try {const devices = deviceManager.getTrustedDeviceListSync();return devices.map(device => device.deviceId);} catch (error) {console.error(`获取设备列表失败: ${(error as BusinessError).message}`);return [];}}// 发布跨设备事件private async publishDistributedEvent(event: string, params: Record<string, Object>) {try {const devices = this.getTrustedDevices();if (devices.length > 0) {// 向所有可信设备发布事件await commonEventManager.publish(event, {parameters: params,devices: devices // 指定目标设备});console.log(`跨设备事件发布成功,目标设备: ${devices.length}个`);} else {console.log('无可信设备,仅在本地发布');await commonEventManager.publish(event, { parameters: params });}} catch (error) {console.error(`跨设备事件发布失败: ${(error as BusinessError).message}`);}}// 订阅跨设备事件private async subscribeDistributedEvent() {const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {events: ['com.example.DISTRIBUTED_ACTION'],isDistributed: true // 关键:启用分布式订阅};try {const subscriber = await commonEventManager.createSubscriber(subscribeInfo);subscriber.on('receive', (event: commonEventManager.CommonEventData) => {console.log(`收到跨设备事件: ${event.event}`);console.log(`来源设备: ${event.deviceId}`);console.log(`事件数据: ${JSON.stringify(event.parameters)}`);// 处理跨设备事件this.handleDistributedEvent(event);});console.log('跨设备事件订阅成功');} catch (error) {console.error(`跨设备事件订阅失败: ${(error as BusinessError).message}`);}}private handleDistributedEvent(event: commonEventManager.CommonEventData) {// 实现跨设备事件处理逻辑console.log(`处理来自设备 ${event.deviceId} 的事件`);}
}
4. 后台持续任务处理
为确保事件处理在后台持续运行,需要使用BackgroundTaskManager
申请后台权限。
4.1 后台任务配置与申请
首先,在module.json5
中声明后台权限:
{"module": {"requestPermissions": [{"name": "ohos.permission.KEEP_BACKGROUND_RUNNING","reason": "$string:background_permission_reason","usedScene": {"abilities": ["MainAbility"],"when": "always"}}]}
}
然后在代码中申请后台任务权限:
import backgroundTaskManager from '@ohos.resources.backgroundTaskManager';
import { BusinessError } from '@ohos.base';@Entry
@Component
struct BackgroundEventDemo {private backgroundTaskId: number = 0;// 申请后台任务权限private async requestBackgroundPermission() {try {const result = await backgroundTaskManager.requestSuspendDelay();console.log('后台任务权限申请成功');// 注册后台任务回调this.backgroundTaskId = await backgroundTaskManager.startBackgroundRunning(backgroundTaskManager.BackgroundMode.DATA_PROCESSING,{// 任务配置isPersistent: true, // 持久化任务notificationContent: {title: '后台事件处理中',text: '应用正在后台处理事件'}});console.log(`后台任务启动成功,ID: ${this.backgroundTaskId}`);} catch (error) {console.error(`后台任务申请失败: ${(error as BusinessError).message}`);}}// 停止后台任务private async stopBackgroundTask() {if (this.backgroundTaskId !== 0) {try {await backgroundTaskManager.stopBackgroundRunning(this.backgroundTaskId);console.log('后台任务已停止');} catch (error) {console.error(`停止后台任务失败: ${(error as BusinessError).message}`);}}}build() {Column() {Button('启动后台事件监听').onClick(() => {this.requestBackgroundPermission();}).margin(10).width('80%')Button('停止后台监听').onClick(() => {this.stopBackgroundTask();}).margin(10).width('80%')}.width('100%').height('100%')}
}
5. 实战案例:后台数据同步器
以下是一个完整的后台数据同步器示例,结合事件订阅和后台任务:
import commonEventManager from '@ohos.commonEventManager';
import commonEvent from '@ohos.commonEvent';
import backgroundTaskManager from '@ohos.resources.backgroundTaskManager';
import { BusinessError } from '@ohos.base';@Entry
@Component
struct BackgroundDataSync {private subscriber: commonEventManager.CommonEventSubscriber | null = null;private backgroundTaskId: number = 0;@State syncStatus: string = '未启动';// 订阅网络变化事件private async setupNetworkListener() {const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {events: [commonEvent.NETWORK_AVAILABLE]};try {this.subscriber = await commonEventManager.createSubscriber(subscribeInfo);this.subscriber.on('receive', (event: commonEventManager.CommonEventData) => {console.log('网络状态变化,触发后台同步');this.syncDataInBackground();});console.log('网络监听器设置成功');} catch (error) {console.error(`网络监听设置失败: ${(error as BusinessError).message}`);}}// 后台数据同步private async syncDataInBackground() {this.syncStatus = '同步中...';try {// 模拟网络请求console.log('开始在后台同步数据');// 实际项目中这里可能是API调用或数据库操作await new Promise(resolve => setTimeout(resolve, 2000));console.log('后台数据同步完成');this.syncStatus = `最后同步: ${new Date().toLocaleTimeString()}`;// 发布同步完成事件await commonEventManager.publish('com.example.DATA_SYNC_COMPLETE', {result: 'success',timestamp: Date.now()});} catch (error) {console.error(`数据同步失败: ${(error as BusinessError).message}`);this.syncStatus = '同步失败';}}// 启动后台同步服务private async startSyncService() {// 申请后台权限try {this.backgroundTaskId = await backgroundTaskManager.startBackgroundRunning(backgroundTaskManager.BackgroundMode.DATA_PROCESSING,{isPersistent: true,notificationContent: {title: '数据同步服务运行中',text: '应用正在后台保持数据同步'}});await this.setupNetworkListener();this.syncStatus = '监听中,等待网络变化...';console.log('后台同步服务启动成功');} catch (error) {console.error(`后台服务启动失败: ${(error as BusinessError).message}`);}}// 停止服务private async stopSyncService() {if (this.subscriber) {await commonEventManager.unsubscribe(this.subscriber);this.subscriber = null;}if (this.backgroundTaskId !== 0) {await backgroundTaskManager.stopBackgroundRunning(this.backgroundTaskId);this.backgroundTaskId = 0;}this.syncStatus = '已停止';console.log('同步服务已停止');}aboutToDisappear() {this.stopSyncService();}build() {Column() {Text('后台数据同步器').fontSize(20).margin(10)Text(`状态: ${this.syncStatus}`).fontSize(16).margin(10)Button('启动后台同步').onClick(() => {this.startSyncService();}).margin(10).width('80%')Button('手动同步').onClick(() => {this.syncDataInBackground();}).margin(10).width('80%')Button('停止服务').onClick(() => {this.stopSyncService();}).margin(10).width('80%')}.width('100%').height('100%')}
}
6. 性能优化与最佳实践
-
事件过滤:精确订阅需要的事件类型,避免不必要的通知。
// 好:精确订阅特定事件 const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {events: [commonEvent.SCREEN_ON, commonEvent.SCREEN_OFF] };// 不好:订阅过多不必要的事件 const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {events: [commonEvent.*] // 避免这样使用 };
-
后台任务精简:后台处理逻辑应轻量高效,避免耗电和资源占用。
// 好:高效的后台处理 private async handleBackgroundEvent() {// 只执行必要的轻量操作await this.updateEssentialData(); }// 不好:在后台执行重操作 private async handleBackgroundEvent() {// 避免在后台执行大量计算或频繁网络请求await this.downloadLargeFiles(); // 不适合在后台执行 }
-
及时取消订阅:在组件销毁或页面消失时取消事件订阅。
aboutToDisappear() {if (this.subscriber) {commonEventManager.unsubscribe(this.subscriber);} }
-
分布式事件优化:跨设备事件应压缩数据量,减少网络传输。
// 好:只发送必要数据 await commonEventManager.publish('user_update', {parameters: {userId: '123',// 只发送变更字段updatedFields: ['name', 'avatar']} });
-
错误处理与重试:实现健壮的错误处理和重试机制。
private async safePublishEvent(event: string, params: Record<string, Object>, retries = 3) {for (let i = 0; i < retries; i++) {try {await commonEventManager.publish(event, { parameters: params });return; // 成功则退出} catch (error) {if (i === retries - 1) {throw error; // 最后一次失败后抛出}await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒后重试}} }
7. 总结
HarmonyOS 5的事件订阅与通知机制为后台事件处理提供了强大支持,关键要点包括:
- 系统事件订阅:通过
commonEventManager
订阅系统事件,实现后台响应。 - 自定义事件:支持应用定义和发布自己的事件,实现组件间解耦。
- 跨设备同步:利用分布式能力实现事件在多设备间同步触发。
- 后台持久化:使用
BackgroundTaskManager
确保事件处理在后台持续运行。 - 性能优化:通过事件过滤、精简任务和及时取消订阅提升性能。
通过合理利用这些能力,开发者可以构建出响应迅速、跨设备协同的后台服务,提升用户体验和应用价值。
需要参加鸿蒙认证的请点击 鸿蒙认证链接