OpenHarmony开发者论坛

标题: OpenHarmony公共事件基本原理解 [打印本页]

作者: Laval社区小助手    时间: 2024-1-8 11:25
标题: OpenHarmony公共事件基本原理解
[md]## 简介

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

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

* **系统公共事件:系统将收集到的事件信息,根据系统策略发送给订阅该事件的用户程序。 例如:系统关键服务发布的系统事件(例如:hap安装,更新,卸载等)。**
* **自定义公共事件:应用自定义一些公共事件用来实现跨应用的事件通信能力。**

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

![](file:///C:/Users/kuangansheng/Desktop/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E5%85%AC%E5%BC%80%E8%AF%BE%E7%A8%8B/OpenHarmony%E5%85%AC%E5%85%B1%E4%BA%8B%E4%BB%B6%E7%9A%84%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86/img/ces.png?lastModify=1686127308)

![](https://devpress.csdnimg.cn/620403828bdd46628db2389a7efdabe6.png)

**commonEvent接口的方法如下:**

![](file:///C:/Users/kuangansheng/Desktop/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E5%85%AC%E5%BC%80%E8%AF%BE%E7%A8%8B/OpenHarmony%E5%85%AC%E5%85%B1%E4%BA%8B%E4%BB%B6%E7%9A%84%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86/img/commonEventUsage.png?lastModify=1686127308)

![](https://devpress.csdnimg.cn/90e33e7056e9450393049667499447ff.png)

## 名词解释

### 订阅者信息(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](https://gitee.com/openharmony/do ... ber?login=from_csdn)

| **方法名称**              | **描述**                                                                             |
| ------------------------------- | ------------------------------------------------------------------------------------------ |
| **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)

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

| **名称**                  | **类型**                    | **必填** | **描述**                           |
| ------------------------------- | --------------------------------- | -------------- | ---------------------------------------- |
| **bundleName**            | **string**                  | **否**   | **表示包名称。**                   |
| **code**                  | **number**                  | **否**   | **表示公共事件的结果代码。**       |
| **data**                  | **string**                  | **否**   | **表示公共事件的自定义结果数据。** |
| **subscriberPermissions** | **Array**<**string>** | **否**   | **表示订阅者的权限。**             |
| **isOrdered**             | **boolean**                 | **否**   | **表示是否是有序事件。**           |
| **isSticky**              | **boolean**                 | **否**   | **表示是否是粘性事件。**           |
| **parameters**            | **{[key: string]: any}**    | **否**   | **表示公共事件的附加信息。**       |

#### **有序公共事件:**

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

#### **粘性公共事件:**

> **非粘性公共事件: 公共事件的订阅动作必须在公共事件发布之前进行。**
>
> **必须订阅者先订阅,然后公共事件发布,订阅者才可以接收到公共事件发布的信息。**
>
> **粘性公共事件: 公共事件的订阅动作可以在公共事件发布之后进行。**
>
> **可以先发布公共事件,然后订阅者再订阅,依然可以收到公共事件发布的信息。**

## 公共事件开发指导:

### 订阅、退订公共事件

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

**系统公共事件名称请参考**[CommonEvent文档/公共事件列表](https://gitee.com/openharmony/do ... %A8?login=from_csdn)

```
//步骤一: 导入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订阅公共事件。**

### 时序图如下:

![](https://devpress.csdnimg.cn/21978e81137f4d76a5717ddee5356122.png)

![](file:///C:/Users/kuangansheng/Desktop/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E8%AF%BE%E7%A8%8B%E6%A1%88%E4%BE%8BFAQ/%E5%85%AC%E5%BC%80%E8%AF%BE%E7%A8%8B/OpenHarmony%E5%85%AC%E5%85%B1%E4%BA%8B%E4%BB%B6%E7%9A%84%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86/img/demo1.png?lastModify=1686127308)

### 应用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/do ... apis-commonEvent.md](https://gitee.com/openharmony/do ... .md?login=from_csdn)
[/md]




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5