OpenHarmony公共事件基本原理

鸿蒙小青娃 2023-03-13 14:12:33

简介

OpenHarmony通过CES(Common Event Service,公共事件服务)为应用程序提供订阅、发布、退订公共事件的能力。

公共事件根据发送方不同可分为系统公共事件和自定义公共事件。

  • 系统公共事件:系统将收集到的事件信息,根据系统策略发送给订阅该事件的用户程序。 例如:系统关键服务发布的系统事件(例如:hap安装,更新,卸载等)。

  • 自定义公共事件:应用自定义一些公共事件用来实现跨应用的事件通信能力。

每个应用都可以按需订阅公共事件,订阅成功且公共事件发布,系统会把其发送给应用。这些公共事件可能来自系统、其他应用和应用自身。

img

commonEvent接口的方法如下:

img

名词解释

订阅者信息(CommonEventSubscribeInfo)

用于设置订阅的一些基本信息,在创建订阅者时使用。

名称读写属性类型必填描述
events只读Array<string>表示订阅的公共事件,一个订阅者可以订阅多个公共事件。
publisherPermission只读string表示发布者的权限。发布者必须具有该权限才可以发布公共事件给该订阅者,该订阅者只接收具有该权限的发布者发布的公共事件。
publisherDeviceId只读string表示设备ID,该值必须是同一ohos网络上的现有设备ID。
userId只读number表示用户ID。此参数是可选的,默认值当前用户的ID。如果指定了此参数,则该值必须是系统中现有的用户ID。
priority只读number表示订阅者的优先级,值的范围是-100到1000。数值越大,订阅者的优先级别越高,在有序公共事件发布时越先接收到发布信息。

写法示例:

let subscribeInfo: any = {
    events: ["event1","event2"],
    userId: 100,
    priority: 200,
    ...
}

订阅者(Subscriber)

用于作为订阅公共事件的载体,订阅公共事件并获取公共事件传递而来的参数。详细信息请参考CommonEvent文档/CommonEventSubscriber

方法名称描述
getCode获取公共事件的结果代码
setCode设置公共事件的结果代码
getData获取公共事件的结果数据
setData设置公共事件的结果数据
setCodeAndData设置公共事件的结果代码和结果数据
isOrderedCommonEvent查询当前公共事件的是否为有序公共事件
isStickyCommonEvent检查当前公共事件是否为一个粘性事件
abortCommonEvent取消当前的公共事件,仅对有序公共事件有效,取消后,公共事件不再向下一个订阅者传递
clearAbortCommonEvent清除当前公共事件的取消状态,仅对有序公共事件有效
getAbortCommonEvent获取当前有序公共事件是否取消的状态
getSubscribeInfo获取订阅者的订阅信息
finishCommonEvent结束当前有序公共事件

公共事件数据(CommonEventData)

通过订阅者成功订阅公共事件之后,返回的订阅的公共事件的一些基本信息。

名称读写属性类型必填描述
event只读string表示当前接收的公共事件名称。
bundleName只读string表示包名称。
code只读number表示公共事件的结果代码,用于传递int类型的数据,默认为0。
data只读string表示公共事件的自定义结果数据,用于传递string类型的数据。
parameters只读{[key: string]: any}表示公共事件的附加信息。

公共事件发布信息(CommonEventPublishData)

在发布公共事件时使用,用于设置发布的公共事件的一些基本信息。

名称类型必填描述
bundleNamestring表示包名称。
codenumber表示公共事件的结果代码。
datastring表示公共事件的自定义结果数据。
subscriberPermissionsArray<string>表示订阅者的权限。
isOrderedboolean表示是否是有序事件。
isStickyboolean表示是否是粘性事件。
parameters{[key: string]: any}表示公共事件的附加信息。

有序公共事件:

当一个无序公共事件发布时,该公共事件的所有订阅者会同时收到发布信息。

当一个有序公共事件发布时,该公共事件的所有订阅者会根据优先级高低依次收到发布信息。

粘性公共事件:

非粘性公共事件: 公共事件的订阅动作必须在公共事件发布之前进行。

​ 必须订阅者先订阅,然后公共事件发布,订阅者才可以接收到公共事件发布的信息。

粘性公共事件: 公共事件的订阅动作可以在公共事件发布之后进行。

​ 可以先发布公共事件,然后订阅者再订阅,依然可以收到公共事件发布的信息。

公共事件开发指导:

订阅、退订公共事件

  1. 设置订阅信息(公共事件名称、订阅者优先级等)
  2. 使用订阅信息创建订阅者
  3. 使用订阅者订阅、退订

系统公共事件名称请参考CommonEvent文档/公共事件列表

//步骤一: 导入commonEvent模块
import commonEvent from "@ohos.commonEvent";

//步骤二: 创建订阅信息,订阅者信息的数据类型及包含的参数请参考名词解释
let subscribeInfo : any = {
    events : ["testEvent"],     //要订阅的公共事件
    userId : 100,                 //用户Id
    priority : 1,                //该订阅者的优先级
    ...
}

let subscriberA = undefined
    
//步骤三:创建订阅者
commonEvent.createSubscriber(subscribeInfo, (err, subscriber) => {
              if (err?.code) {
                console.log("[CommonEvent] CreateSubscriber CallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent] CreateSubscriber")
                this.subscriberA = subscriber   //将创建订阅者回调生成的订阅者赋给subscriberA
              }
            })
            
//步骤四: 订阅公共事件
commonEvent.subscribe(subscriberA, (err, data) => {
              if (err?.code) {
                console.log("[CommonEvent] SubscribeCallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent] SubscribeCallBack data=" + JSON.stringify(data))
              }
            })
            
//退订公共事件
commonEvent.unsubscribe(subscriberA, err=>{
    if(err?.code){
       console.log("[CommonEvent] unSubscribeCallBack err=" + JSON.stringify(err))
    }else{
        console.log("[CommonEvent] unSubscribeCallBack succeed")
    }
})

发布公共事件

开发者可以发布四种公共事件:无序的公共事件、有序的公共事件、带权限的公共事件、粘性的公共事件。

import commonEvent from "@ohos.commonEvent";

//步骤一:设置公共事件发布信息,具体参数信息请参考名词解释
let commonEventPublishData = {
           data : "test data",
           isOrdered: true,          //设置为有序公共事件
           code : 13178,
           isSticky : true,        //设置为粘性公共事件
           parameters : {            //公共事件发布时,携带的参数
                   a : "aa",
                   b : 'bb',
                   c : 'cc'
           }
    }

//步骤二:发布公共事件testEvent
commonEvent.publish("testEvent", commonEventPublishData,(err) => {
              if (err?.code) {
                Logger.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
              } else {
                Logger.info("[CommonEvent] Publish testEvent succeed ")
              }
            })

开发示例

此处以应用间的公共事件发布、订阅为例,应用A发布公共事件,应用B订阅公共事件。

时序图如下:

img

应用A中代码如下:

三个操作: 创建订阅者、订阅、发布公共事件testEvent

import commonEvent from '@ohos.commonEvent';

@Entry
@Component
struct TestA {
  @State publishCount: number = 0
  @State createSubscriberCount: number = 0
  @State SubscribetestEventCount: number = 0

  subscriberOftestEvent : any = undefined

  build() {
    Row() {
      Column() {

          //步骤一:创建订阅者
        Button('Create Subscriber Of testEvent: '+ this.createSubscriberCount).type(ButtonType.Capsule).fontSize(30).margin({bottom: 15})
          .onClick(()=>{
            this.createSubscriberCount+=1

            let subscribeInfo: any= {
              events: ["testEvent"]
            }

            commonEvent.createSubscriber(subscribeInfo, (err, subscriber) => {
              if (err.code) {
                console.log("[CommonEvent]CreateSubscriberCallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent]CreateSubscriber")
                this.subscriberOftestEvent = subscriber
              }
            })

          })

        //步骤二:订阅公共事件testEvent
        Button('Subscribe testEvent: '+ this.SubscribetestEventCount).type(ButtonType.Capsule).fontSize(30).margin({bottom: 30})
          .onClick(()=>{
            console.log("come in !!!")
            this.SubscribetestEventCount+=1

            console.log(`this.subscriberOftestEvent : ${JSON.stringify(this.subscriberOftestEvent)}`)
            commonEvent.subscribe(this.subscriberOftestEvent, (err, data) => {

              if (err?.code) {
                console.log("[CommonEvent] SubscribeCallBack err=" + JSON.stringify(err))
              } else {
                this.SubscribetestEventCount+=1
                console.log("[CommonEvent] SubscribeCallBack data=" + JSON.stringify(data))
              }
            })

          })

        //步骤三:发布公共事件testEvent
        Button('Publish testEvent : ' + this.publishCount).fontSize(30).margin({bottom: 15})
          .onClick(()=>{
            this.publishCount+=1
            commonEvent.publish("testEvent", (err) => {
              console.log(`err${JSON.stringify(err)}`)
              if (err?.code) {
                console.log("[CommonEvent] PublishCallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent] Publish Succeed ")
              }
            })
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

应用B中代码如下:

只订阅应用A发布的公共事件testEvent

import commonEvent from '@ohos.commonEvent';

@Component
@Entry
struct TestB{

  @State dCount : number = 0
  @State result : string = "待订阅"
  @State createSubscriberInfo : string = "待创建"
  subscriber : any = undefined
  subscribeInfo: any= {
    events: ["testEvent"],
  }

  build(){
    Column(){
      Column(){

        //步骤一:创建订阅者
        Button('创建订阅者: '+ this.createSubscriberInfo).type(ButtonType.Capsule).fontSize(40)
          .onClick(()=>{

            //创建订阅者回调
            commonEvent.createSubscriber(this.subscribeInfo, (err, subscriber) => {
              if (err?.code) {
                console.log("[CommonEvent] CreateSubscriberCallBack err=" + JSON.stringify(err))
              } else {
                console.log("[CommonEvent] CreateSubscriber")
                this.subscriber = subscriber
                this.createSubscriberInfo = "Create subscriber succeed"
              }
            })

          })

        //步骤二:订阅
        Button('订阅公共事件testEvent: '+ this.dCount+this.result).type(ButtonType.Capsule).fontSize(40)
          .onClick(()=>{
            
            commonEvent.subscribe(this.subscriber, (err, data) => {
              if (err?.code) {
                console.log("[CommonEvent]SubscribeCallBack err=" + JSON.stringify(err))
              } else {
                this.dCount+=1
                console.log("[CommonEvent]SubscribeCallBack data=" + JSON.stringify(data))
                this.result = "receive, event = " + data.event + ", data = " + data.data + ", code = " + data.code
              }
            })
          })
      }
    }

  }

}

操作流程:

  1. A应用创建订阅者、订阅

  2. B应用创建订阅者、订阅

  3. A应用发布公共事件testEvent

    (顺序不能乱,因为这里发布的不是粘性公共事件)

公共事件调试助手cem

公共事件与通知提供了供开发者查看公共事件信息及通知信息、发布公共事件等一些调试功能的工具。

这些工具已经随系统集成,开发者进入shell环境,可以直接调用相关命令。

publish发布公共事件

参数如下表所示

参数参数说明
-e/--event必选参数,发布事件名称
-s/--sticky可选参数,发布粘性事件,默认发布非粘性事件
-o/--ordered可选参数,发布有序事件,默认发布无序事件
-c/--code可选参数,公共事件结果码
-d/--data可选参数,公共事件携带数据
-h/--help帮助信息

用法示例:

# 发布名称为testevent的公共事件
cem publish --event "testevent"

# 发布名称为testevent的粘性有序公共事件,该事件的结果码为100,携带数据内容为“this is data”
cem publish -e "testevent" -s -o -c 100 -d "this is data"

dump打印公共事件相关信息

参数如下表所示

参数参数说明
-a/--all打印开机以来所有已发送的公共事件及其具体信息
-e/--event查询特定名称事件的具体信息
-h/--help帮助信息

用法示例:

# 打印公共事件名称为testevent的具体信息
cem dump -e "testevent"

打印出来的信息如下:

Subscribers:    No information
Sticky Events:  No information
Pending Events: No information
History Events: Total 1 information
NO 1
        Time: 20170805 10:12 AM
        PID: 2099
        UID: 20010037
        USERID: ALL_USER                                        
        BundleName: com.ohos.dtest
        RequiredPermission:                            # 发布者所要求的权限
        IsSticky: false                                # 发布的事件是否是粘性事件
        IsOrdered: false                            # 发布的事件是否是有序事件
        IsSystemApp: false                            # 发布者是否是系统应用
        IsSystemEvent: false                        # 发布的事件是否是系统事件
        Want:
                Action: testevent                    # 发布的事件名称
                Entity:
                Scheme:
                Uri:
                Flags: 0
                Type:
                BundleName:
                AbilityName:
                DevicedID:
        Code: 0                                        # 有序事件的结果码,仅在有序事件下有效
        Data:                                        # 事件携带的数据
        HasLastSubscriber: false                    # 是否有最终订阅者,仅在有序事件下有效
        EventState: RECEIVED                        # 事件发送状态
        ReceiverTime: 0
        DispatchTime: 0
        ResultAbort: false                            # 事件是否被终止,仅在有序事件下有效
        Subscribers:    Total 1 subscribers            # 所有可以接收该事件的订阅者信息
        NO 1
                Time: 20170805 10:11 AM
                BundleName: com.ohos.dtest            # 事件订阅者的包名
                Priority: 0                            # 订阅者的优先级,仅在订阅有序
                USERID: ALL_USER                    # 作为子系统订阅者,没有指定用户ID的情况下,默认订阅所有的用户;                                                                            # 如果是三方应用,则只能订阅这个包对应的用户ID,且不允许订阅其他的用户。
                Permission:                            # 订阅者所要求的权限
                DevicedID:
                IsFreeze: false                         # 订阅者是否被冻结,被冻结的订阅者将无法收到事件
                FreezeTime:  -
                EventState: DELIVERED                 # 订阅者接收状态
  • 发布者EventState有三种状态:

    • IDLE表示没有订阅者或者有序事件正在等待处理下一个订阅者;
    • RECEIVEING表示该订阅者们仍然在处理该事件;
    • RECEIVED表示所有订阅已经处理完成,事件发送完成。
  • 订阅者EventState有四种状态:

    • PENDING表示订阅者仍在等待处理事件;
    • DELIVERED表示订阅者已经完成接收;
    • SKIPPED表示该订阅者不能接收该事件,常见于权限不匹配或者订阅者被冻结的情况下;
    • TIMEOUT仅出现在有序事件下,表示该订阅者处理事件超时。

参考文献

[1]OpenHarmony公共事件.https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-commonEvent.md

...全文
1556 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

506

社区成员

发帖
与我相关
我的任务
社区描述
OpenHarmony开发者社区
其他 企业社区
社区管理员
  • csdnsqst0025
  • shewaliujingli
  • BaoWei
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧