尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

鸿蒙新特性实战:@ohos.commonEventManager — 公共事件发布订阅与系统事件总线

鸿蒙新特性实战:@ohos.commonEventManager — 公共事件发布订阅与系统事件总线
📅 发布时间:2026/7/12 17:50:30

引言

在移动应用架构中,组件间的通信始终是一个核心命题。HarmonyOS 的 Stage 模型将 UI 页面与后台 Ability 隔离在不同生命周期中,客观上要求一套可靠的跨组件、跨进程通信机制。Android 开发者熟悉 BroadcastReceiver,iOS 开发者熟悉 NotificationCenter——而 HarmonyOS NEXT 的答案是@ohos.commonEventManager,一套完整的公共事件(Common Event)发布/订阅系统。

与@ohos.events.emitter的进程内事件总线不同,commonEventManager工作在系统服务层——事件经由系统 Common Event Service 路由,可以实现跨应用、跨进程的事件传递。系统本身也通过这套机制广播电池状态、网络连接、时区变化等底层状态事件(即Support枚举中定义的各类系统公共事件)。

本文将构建一个事件总线实验室Demo,从零开始演示自定义事件的完整生命周期:创建订阅者(Subscriber)、注册事件监听、发布带数据的公共事件、处理有序事件(Ordered Event),并以实时日志追踪每一步的状态流转。

读完本文,你将掌握:

  • 订阅者创建:createSubscriberSync()— 同步构建 CommonEventSubscriber
  • 事件订阅:subscribe()— 注册带事件匹配规则的持久监听
  • 事件发布:publish()— 发布基本事件 / 带 code + data 的结构化事件
  • 有序事件:isOrdered— 有序事件的发布与结果码处理
  • 数据流:CommonEventPublishData→CommonEventData— 发布端到接收端的数据传递
  • 系统事件:Support枚举 — 30+ 系统公共事件的分类与用途

环境与权限

@ohos.commonEventManager属于BasicServicesKit工具包,自 API 9 开始提供。导入方式:

import{commonEventManager}from'@kit.BasicServicesKit';

重要发现:发布和订阅自定义事件不需要任何权限。只有以下操作需要额外权限:

操作所需权限级别
发布自定义事件无需权限—
订阅自定义事件无需权限—
发布粘性事件 (isSticky)ohos.permission.COMMONEVENT_STICKYsystem_grant
订阅部分系统事件视具体事件而定部分需 system 权限

对于大多数应用场景(应用内跨组件通信、自定义事件总线),commonEventManager是零权限开销的。本文 Demo 也无需任何权限声明即可运行。

一、核心数据结构

在深入 API 使用之前,先理解四个关键接口。

1.1 CommonEventSubscribeInfo — 订阅配置

interfaceCommonEventSubscribeInfo{events:Array<string>;// 要订阅的事件名列表(支持多事件匹配)publisherPermission?:string;// 发布者所需权限(过滤来源)publisherDeviceId?:string;// 发布者设备 ID(分布式场景)userId?:number;// 发布者用户 IDpriority?:number;// 订阅者优先级(-100 ~ +1000)publisherBundleName?:string;// 发布者 Bundle Name(精确定向)}

events是唯一必填字段,支持字符串数组——一个 Subscriber 可以同时匹配多个事件名。priority在有序事件中至关重要:高优先级的订阅者先收到事件,并有机会通过setCode()/setData()影响下游订阅者。

匹配规则:

  • 事件名精确匹配时,订阅者收到事件
  • 若指定了publisherBundleName,仅接收该 Bundle 发布的事件
  • 若指定了publisherPermission,仅接收声明了该权限的发布者的事件

1.2 CommonEventPublishData — 发布数据

interfaceCommonEventPublishData{bundleName?:string;// 限定接收者的 Bundle Namecode?:number;// 结果码(默认 0)data?:string;// 字符串数据(最大 64KB)subscriberPermissions?:Array<string>;// 接收者所需权限isOrdered?:boolean;// 是否有序事件(默认 false)isSticky?:boolean;// 是否粘性事件(需 COMMONEVENT_STICKY 权限)parameters?:{[key:string]:any};// 附加键值对}

code和data是发布者向订阅者传递信息的两个主通道。code通常用于状态码(类似 HTTP 状态码),data用于承载字符串数据。parameters提供了更灵活的键值对扩展——可以传递任意 JSON 可序列化的结构。

注意:data字段限制 64KB,如果需要传输更大的数据,应通过文件路径或 URI 传递。

1.3 CommonEventData — 接收数据

interfaceCommonEventData{event:string;// 事件名称bundleName?:string;// 发布者的 Bundle Namecode?:number;// 发布时传入的 codedata?:string;// 发布时传入的 dataparameters?:{[key:string]:any};// 发布时传入的 parameters}

订阅者在回调中收到CommonEventData,它是CommonEventPublishData的"镜像"——发布时的code、data、parameters原封不动传递到接收端。event字段告诉订阅者当前触发的是哪个事件(当订阅了多个事件时尤为重要)。

1.4 CommonEventSubscriber — 订阅者实例

interfaceCommonEventSubscriber{getCode(callback:AsyncCallback<number>):void;getCodeSync():number;// 同步获取当前结果码setCode(code:number):Promise<void>;setCodeSync(code:number):void;// 同步设置结果码getData(callback:AsyncCallback<string>):void;getDataSync():string;// 同步获取当前结果数据setData(data:string):Promise<void>;setCodeAndData(code:number,data:string):Promise<void>;isOrderedCommonEventSync():boolean;// 是否有序事件isStickyCommonEventSync():boolean;// 是否粘性事件abortCommonEventSync():void;// 中断有序事件传递finishCommonEvent():Promise<void>;// 完成有序事件处理getSubscribeInfoSync():CommonEventSubscribeInfo;// 获取订阅信息}

CommonEventSubscriber不仅是订阅句柄,在有序事件中,它还是事件处理的控制点。通过setCode()/setData(),订阅者可以修改传递给下一个订阅者的结果;通过abortCommonEventSync(),可以终止事件继续向后传递。

二、完整生命周期

一个完整的自定义事件流包含五个步骤:

2.1 创建订阅者

import{commonEventManager}from'@kit.BasicServicesKit';// 定义订阅信息letsubscribeInfo:commonEventManager.CommonEventSubscribeInfo={events:['com.example.MY_EVENT']};// 同步创建 Subscriber(API 10+)letsubscriber=commonEventManager.createSubscriberSync(subscribeInfo);

createSubscriberSync()是 API 10 引入的同步方法,直接返回CommonEventSubscriber实例。如果你的项目最低 API 版本是 9,可以使用 Promise 版本:

letsubscriber=awaitcommonEventManager.createSubscriber(subscribeInfo);

CommonEventSubscribeInfo的events数组支持多个事件名——一个 Subscriber 可以同时监听多个不同的事件。这比 Android BroadcastReceiver 的 IntentFilter 设计更简洁。

2.2 订阅事件

commonEventManager.subscribe(subscriber,(err:Error,data:commonEventManager.CommonEventData)=>{if(err){console.error('订阅失败: '+JSON.stringify(err));return;}console.log('收到事件: '+data.event);console.log(' code: '+(data.code||0));console.log(' data: '+(data.data||''));console.log(' bundleName: '+(data.bundleName||'(本应用)'));});

subscribe()注册一个异步回调,当匹配的事件被发布时,系统会调用该回调并传入CommonEventData。回调在主线程执行——如果处理逻辑较重,应考虑异步化。

2.3 发布事件

// 基本发布:仅事件名commonEventManager.publish('com.example.MY_EVENT',(err:Error)=>{if(err){console.error('发布失败: '+JSON.stringify(err));}else{console.log('发布成功');}});// 带数据发布letpublishData:commonEventManager.CommonEventPublishData={code:200,data:'{"msg":"Hello CommonEvent!"}',isOrdered:false};commonEventManager.publish('com.example.MY_EVENT',publishData,(err:Error)=>{// ...});

publish()是异步的——事件被提交到系统 Common Event Service 后,由 Service 异步分发给所有匹配的订阅者。发布者不等待订阅者处理完毕。

2.4 取消订阅

commonEventManager.unsubscribe(subscriber);

unsubscribe()传入 Subscriber 实例,系统会移除该订阅者的所有事件监听。未取消的订阅可能导致内存泄漏——建议在页面aboutToDisappear()生命周期中清理。

2.5 完整示例:计数器事件广播

import{commonEventManager}from'@kit.BasicServicesKit';// 发布端letpublishInfo:commonEventManager.CommonEventPublishData={code:1,data:'increment'};commonEventManager.publish('com.example.COUNTER',publishInfo,(err:Error)=>{console.log('计数器事件已发布');});// 接收端letinfo:commonEventManager.CommonEventSubscribeInfo={events:['com.example.COUNTER']};letsub=commonEventManager.createSubscriberSync(info);commonEventManager.subscribe(sub,(err:Error,data:commonEventManager.CommonEventData)=>{if(data.code===1&&data.data==='increment'){// 执行计数器加一操作}});


三、有序事件(Ordered Event)

有序事件是commonEventManager的独特设计之一。当isOrdered设为true时,事件按订阅者优先级串行传递——高优先级订阅者先收到,可以修改结果码/数据,甚至可以中断传递链。

3.1 工作原理

发布者 publish(isOrdered=true) │ ▼ 订阅者 A (priority=1000) ← 最先收到 │ setCodeAndData(1, 'processed_by_A') ▼ 订阅者 B (priority=500) ← 收到 A 修改后的数据 │ getCodeSync() → 1 │ getDataSync() → 'processed_by_A' │ abortCommonEventSync() ← 中断传递 ▼ 订阅者 C (priority=100) ← 不会收到(已被中断) │ ▼ 发布者回调 → publish 完成

3.2 代码演示

// 发布者发布有序事件letpublishData:commonEventManager.CommonEventPublishData={code:0,data:'original',isOrdered:true// 关键:标记为有序事件};commonEventManager.publish('com.example.ORDERED',publishData,(err:Error)=>{console.log('有序事件发布完成');});// 高优先级订阅者也叫"A"letsubA=commonEventManager.createSubscriberSync({events:['com.example.ORDERED'],priority:1000});commonEventManager.subscribe(subA,(err:Error,data:commonEventManager.CommonEventData)=>{// 修改结果,传递给下游subA.setCodeAndDataSync(1,'processed_by_A');subA.finishCommonEvent();// 必须调用,否则事件链卡住});// 中等优先级订阅者"B"letsubB=commonEventManager.createSubscriberSync({events:['com.example.ORDERED'],priority:500});commonEventManager.subscribe(subB,(err:Error,data:commonEventManager.CommonEventData)=>{letcode=subB.getCodeSync();// → 1(由 A 设置)letd=subB.getDataSync();// → 'processed_by_A'// 中断传递,C 不会收到此事件subB.abortCommonEventSync();subB.finishCommonEvent();});// 低优先级订阅者"C"letsubC=commonEventManager.createSubscriberSync({events:['com.example.ORDERED'],priority:100});commonEventManager.subscribe(subC,(err:Error,data:commonEventManager.CommonEventData)=>{// 当 A 或 B 调用了 abortCommonEventSync() 后,C 不会执行到这里});

关键规则:

  • finishCommonEvent()是必需的——不调用会导致事件链永久阻塞,后续订阅者永远等不到
  • abortCommonEventSync()中断传递,之后的订阅者不会收到事件
  • 优先级值域为 -100 ~ +1000,值越大越先收到

四、系统公共事件(Support 枚举)

Support枚举定义了 30+ 系统公共事件,覆盖了设备管理的数个关键领域:

分类事件名触发时机
设备状态usual.event.BOOT_COMPLETED设备启动完成
设备状态usual.event.SHUTDOWN设备关机
电池usual.event.BATTERY_CHANGED电池状态变化
电池usual.event.BATTERY_LOW低电量
电池usual.event.BATTERY_OKAY电量恢复正常
电源usual.event.POWER_CONNECTED电源连接
电源usual.event.POWER_DISCONNECTED电源断开
屏幕usual.event.SCREEN_ON屏幕点亮
屏幕usual.event.SCREEN_OFF屏幕关闭
时间usual.event.TIME_TICK每分钟计时
时间usual.event.TIME_CHANGED系统时间被修改
时间usual.event.TIMEZONE_CHANGED时区变更
温控usual.event.THERMAL_LEVEL_CHANGED温度等级变化
应用usual.event.PACKAGE_ADDED新应用安装(系统应用)
应用usual.event.PACKAGE_REPLACED应用更新(系统应用)

注意:标有"系统应用"的事件需要 system 权限或系统应用身份才能订阅。普通应用可以自由订阅电池、电源、屏幕、时间、时区等无需权限的事件——这些是打造系统感知型应用的绝佳入口。

以下示例演示订阅电池变化事件:

letinfo:commonEventManager.CommonEventSubscribeInfo={events:[commonEventManager.Support.COMMON_EVENT_BATTERY_CHANGED,commonEventManager.Support.COMMON_EVENT_POWER_CONNECTED]};letsub=commonEventManager.createSubscriberSync(info);commonEventManager.subscribe(sub,(err:Error,data:commonEventManager.CommonEventData)=>{if(data.event===commonEventManager.Support.COMMON_EVENT_BATTERY_CHANGED){console.log('电池状态变化: code='+data.code);}elseif(data.event===commonEventManager.Support.COMMON_EVENT_POWER_CONNECTED){console.log('电源已连接');}});

五、实战 Demo:事件总线实验室

页面结构

事件总线实验室 ├── 状态栏 — 订阅状态 + 已收到事件计数 ├── 事件订阅配置 │ ├── 事件名输入框 │ └── 订阅 / 取消订阅 按钮 ├── 事件发布面板 │ ├── 事件名输入框 │ ├── Code 输入框 │ ├── Data 输入框 │ ├── 有序事件 Toggle │ └── 发布按钮 ├── 事件日志 — 最近 50 条(含时间戳) ├── 系统公共事件参考 — 10 个常用事件 └── 核心 API 参考 — 10 个关键 API

4 个交互点

  1. 订阅自定义事件— 输入事件名,点击"订阅"创建 Subscriber 并注册回调,状态实时反馈
  2. 发布事件— 编辑事件名、code、data,勾选有序/无序,点击"发布"触发;日志立即显示发布成功和接收确认
  3. 有序事件切换— 勾选有序事件 Toggle 后发布,Demo 演示发布端如何通过isOrdered参数控制事件传递模式
  4. 实时事件日志— 所有操作(订阅/取消/发布/接收/异常)均以带时间戳的彩色日志呈现,最近 50 条

核心代码位置

完整代码在dev/entry/src/main/ets/pages/EventBusLabPage.ets(约 330 行),路由已注册为pages/EventBusLabPage。

六、commonEventManager vs events.emitter

HarmonyOS 提供了两个事件机制,理解它们的差异至关重要:

维度commonEventManager@ohos.events.emitter
通信范围跨进程(系统级)进程内
底层机制系统 Common Event Service内存事件表
权限需求无(自定义事件)无
有序事件支持(priority + abort)支持(EventPriority)
粘性事件支持(需权限)不支持
系统事件Support 枚举(30+)不支持
适用场景跨应用通信、系统监听页面/组件解耦

简而言之:跨进程通信用 commonEventManager,进程内解耦用 emitter。本文 Demo 虽然只在单应用内收发,但展示了完整的commonEventManagerAPI 栈,便于扩展到跨应用场景。

七、与 Android BroadcastReceiver 的对比

维度Android BroadcastReceiverHarmonyOS commonEventManager
注册方式动态注册 + 静态注册(Manifest)createSubscriberSync + subscribe
传递数据Intent.putExtra()code + data + parameters
有序广播sendOrderedBroadcast()isOrdered + priority + abort
粘性广播sendStickyBroadcast() (Deprecated)isSticky(需权限)
系统广播Intent.ACTION_BATTERY_CHANGED 等Support 枚举
权限控制自定义 permissionpublisherPermission / subscriberPermissions
安全模型较松散(静态注册易被唤醒)严格(需要显式声明接收者权限)

HarmonyOS 的设计更加显式化:发布者必须指定哪些权限的订阅者可以接收事件,订阅者也可以筛选发布者——双向权限校验带来更强的安全保证。

八、最佳实践与注意事项

8.1 生命周期管理

aboutToDisappear():void{if(this.subscriber!==null){commonEventManager.unsubscribe(this.subscriber);this.subscriber=null;}}

页面销毁前务必取消订阅。未清理的 Subscriber 会导致内存泄漏和无效回调。

8.2 主线程回调

subscribe()的回调在主线程执行。如果回调中包含耗时操作(如数据库写入、网络请求),应使用@ohos.worker将逻辑切换到子线程。

8.3 有序事件的 finishCommonEvent

在有序事件中,每个订阅者必须调用finishCommonEvent(),否则事件链会永久阻塞——系统在等待当前订阅者完成处理。这是新手最容易踩的坑。

8.4 事件命名建议

推荐使用反向域名命名法,如com.example.module.ACTION_NAME,避免与系统事件命名冲突。系统事件统一使用usual.event.*前缀。

8.5 data 大小限制

CommonEventPublishData.data最大 64KB。超出此限制会导致发布失败。大数据传输应使用文件路径或分布式数据对象。

九、API 总结表

API返回值说明
commonEventManager.createSubscriberSync(info)CommonEventSubscriber同步创建订阅者(API 10+)
commonEventManager.createSubscriber(info)Promise<CommonEventSubscriber>异步创建订阅者(API 9+)
commonEventManager.subscribe(sub, cb)void订阅事件
commonEventManager.unsubscribe(sub)void取消订阅
commonEventManager.publish(event, cb)void发布简单事件
commonEventManager.publish(event, opts, cb)void发布带数据的事件
Subscriber.getCodeSync()number同步获取结果码
Subscriber.setCodeAndDataSync(code, data)void同步设置结果码和数据
Subscriber.finishCommonEvent()Promise<void>完成有序事件处理
Subscriber.abortCommonEventSync()void中断有序事件传递

十、总结

@ohos.commonEventManager是 HarmonyOS NEXT 的进程间通信主干,提供了一套完整的发布/订阅系统:

  1. 零权限开销:自定义事件的发布和订阅无需任何权限声明
  2. 丰富的传递数据结构:code+data+parameters三层载荷通道
  3. 有序事件链:基于优先级的串行传递,支持结果码修改和传递中断
  4. 系统事件感知:Support枚举提供 30+ 系统公共事件,覆盖电池、电源、屏幕、时间、温控等场景
  5. 安全模型:双向权限校验(发布方限定接收者,订阅方筛选发布者)

这个模块与@ohos.events.emitter(进程内事件)和@ohos.net.http(HTTP 通信)共同构成了 HarmonyOS 应用通信的完整层级——从进程内解耦,到跨组件广播,再到网络请求,开发者可以根据通信场景精准选择对应工具。


相关新闻

  • qFlipper终极安装指南:Flipper Zero固件更新完整教程
  • 云浮黄金贵金属回收六店联荐 | 清奢、璟安、鑫宸覆盖全市五区县,就近变现不踩坑! - 新芸鼎珠宝首饰
  • 固定资产管理系统界面设计:从 8 款开源方案中提炼 5 个高交互性设计模式

最新新闻

  • 探索Android设备Root检测的深度实战:揭秘RootBeer的进阶应用
  • B站用户终极指南:如何用开源工具解锁完整视频体验?
  • 2026年公众号迁移线上公证保姆级教程 - 跑政通
  • Hunyuan3D-Part:基于AI的3D部件分割与形状合成技术解析
  • 终极指南:如何为Phira节奏游戏项目做出你的第一份贡献
  • 自研的降 AIGC 工具和套壳的差在哪?怎么一眼分辨 - 我要发一区

日新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号