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
确保事件处理在后台持续运行。 - 性能优化:通过事件过滤、精简任务和及时取消订阅提升性能。
通过合理利用这些能力,开发者可以构建出响应迅速、跨设备协同的后台服务,提升用户体验和应用价值。
需要参加鸿蒙认证的请点击 鸿蒙认证链接