阅读(1841) (9)

鸿蒙OS 公共事件开发指导

2020-09-16 17:15:14 更新

场景介绍

每个应用都可以订阅自己感兴趣的公共事件,订阅成功后且公共事件发布后,系统会把其发送给应用。这些公共事件可能来自系统、其他应用和应用自身。HarmonyOS 提供了一套完整的 API,支持用户订阅、发送和接收公共事件。发送公共事件需要借助 CommonEventData 对象,接收公共事件需要继承 CommonEventSubscriber 类并实现 onReceiveEvent 回调函数。

接口说明

公共事件相关基础类包含 CommonEventData、CommonEventPublishInfo、CommonEventSubscribeInfo、CommonEventSubscriber 和 CommonEventManager。基础类之间的关系如下图所示:

图1 公共事件基础类关系图 点击放大

CommonEventData

CommonEventData 封装公共事件相关信息。用于在发布、 分发和接收时处理数据。在构造 CommonEventData 对象时,相关参数需要注意以下事项:

  • code 为有序公共事件的结果码,data 为有序公共事件的结果数据,仅用于有序公共事件场景。
  • intent 不允许为空,否则发布公共事件失败。
接口名 描述
CommonEventData() 创建公共事件数据。
CommonEventData(Intent intent) 创建公共事件数据指定 Intent。
CommonEventData(Intent intent, int code, String data) 创建公共事件数据,指定 Intent、code 和 data。
getIntent() 获取公共事件intent。
setCode(int code) 设置有序公共事件的结果码。
getCode() 获取有序公共事件的结果码。
setData(String data) 设置有序公共事件的详细结果数据。
getData() 获取有序公共事件的详细结果数据。

CommonEventPublishInfo

CommonEventPublishInfo 封装公共事件发布相关属性、限制等信息,包括公共事件类型(有序或粘性)、接收者权限等。

有序公共事件:主要场景是多个订阅者有依赖关系或者对处理顺序有要求,例如:高优先级订阅者可修改公共事件内容或处理结果,包括终止公共事件处理;或者低优先级订阅者依赖高优先级的处理结果等。

有序公共事件的订阅者可以通过 CommonEventSubscribeInfo.setPriority() 方法指定优先级,缺省为 0,优先级范围[-1000, 1000],值越大优先级越高。

  • 粘性公共事件:指公共事件的订阅动作是在公共事件发布之后进行,订阅者也能收到的公共事件类型。主要场景是由公共事件服务记录某些系统状态,如蓝牙、WLAN、充电等事件和状态。不使用粘性公共事件机制时,应用可以通过直接访问系统服务获取该状态;在状态变化时,系统服务、硬件需要提供类似 observer 等方式通知应用。

发布粘性公共事件可以通过 setSticky() 方法设置, 发布粘性公共事件需要申请如下权限。声明请参考[表1]。

    "reqPermissions": [{
        "name": "ohos.permission.COMMONEVENT_STICKY",
        "reason": "get right",
        "usedScene": {
           "ability": [
            ".MainAbility"
           ],
           "when": "inuse"
        }
    }, {
    ...
    }]
接口名 描述
CommonEventPublishInfo() 创建公共事件发送信息。
CommonEventPublishInfo(CommonEventPublishInfo publishInfo) 拷贝一个公共事件发送信息。
setSticky(boolean sticky) 设置公共事件的粘性属性。
setOrdered(boolean ordered) 设置公共事件的有序属性。
setSubscriberPermissions(String[] subscriberPermissions) 设置公共事件订阅者的权限,多参数仅第一个生效。

CommonEventSubscribeInfo

CommonEventSubscribeInfo 封装公共事件订阅相关信息,比如优先级、线程模式、事件范围等。

线程模式(ThreadMode):设置订阅者的回调方法执行的线程模式。ThreadMode 有 HANDLER,POST,ASYNC,BACKGROUND 四种模式,目前只支持 HANDLER 模式。

  • HANDLER:在 Ability 的主线程上执行。
  • POST:在事件分发线程执行。
  • ASYNC:在一个新创建的异步线程执行。
  • BACKGROUND:在后台线程执行。
接口名 描述
CommonEventSubscribeInfo(MatchingSkills matchingSkills) 创建公共事件订阅器指定matchingSkills。
CommonEventSubscribeInfo(CommonEventSubscribeInfo) 拷贝公共事件订阅器对象。
setPriority(int priority) 设置优先级,用于有序公共事件。
setThreadMode(ThreadMode threadMode) 指定订阅者的回调函数运行在哪个线程上。
setPermission(String permission) 设置订阅者的权限。
setDeviceId(String deviceId) 指定订阅哪台设备的公共事件。

CommonEventSubscriber

CommonEventSubscriber 封装公共事件订阅者及相关参数。

  • CommonEventSubscriber.AsyncCommonEventResult 类处理有序公共事件异步执行,详见API参考。
  • 目前只能通过调用 [CommonEventManager] 的 subscribeCommonEvent() 进行订阅。
接口名 描述
CommonEventSubscriber(CommonEventSubscribeInfo subscribeInfo) 构造公共事件订阅者实例。
onReceiveEvent(CommonEventData data) 由开发者实现, 在接收到公共事件时被调用。
AsyncCommonEventResult goAsyncCommonEvent() 设置有序公共事件异步执行。
setCodeAndData(int code, String data) 设置有序公共事件的异步结果。
setData(String data) 设置有序公共事件的异步结果数据。
setCode(int code) 设置有序公共事件的异步结果码。
getData() 获取有序公共事件的异步结果数据。
getCode() 获取有序公共事件的异步结果码。
abortComonEvent() 取消当前的公共事件,仅对有序公共事件有效,取消后,公共事件不再向下一个订阅者传递。
getAbortCommonEvent() 获取当前有序公共事件是否取消的状态。
clearAbortCommonEvent() 清除当前有序公共事件abort状态。
isOrderedCommonEvent() 查询当前公共事件的是否为有序公共事件。
isStickyCommonEvent() 查询当前公共事件是为否粘性公共事件。

CommonEventManager

CommonEventManager 是为应用提供订阅、退订和发布公共事件的静态接口类。

方法 描述
publishCommonEvent(CommonEventData event) 发布公共事件。
publishCommonEvent(CommonEventData event, CommonEventPublishInfo publishinfo) 发布公共事件指定发布信息。
publishCommonEvent(CommonEventData event, CommonEventPublishInfo publishinfo, CommonEventSubscriber resultSubscriber) 发布有序公共事件,指定发布信息和最后一个接收者。
subscribeCommonEvent(CommonEventSubscriber subscriber) 订阅公共事件。
unsubscribeCommonEvent(CommonEventSubscriber subscriber) 退订公共事件。

发布公共事件

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

发布无序的公共事件:构造 CommonEventData 对象,设置 Intent,通过构造operation 对象把需要发布的公共事件信息传入 intent 对象。然后调用 CommonEventManager.publishCommonEvent(CommonEventData) 接口发布公共事件。

try {
     Intent intent = new Intent();   
     Operation operation = new Intent.OperationBuilder()
             .withAction("com.my.test")
             .build();
     intent.setOperation(operation);
     CommonEventData eventData = new CommonEventData(intent);
     CommonEventManager.publishCommonEvent(eventData); 
} catch (RemoteException e) {
     HiLog.info(LABEL, "publishCommonEvent occur exception."); 
}

发布携带权限的公共事件:构造 CommonEventPublishInfo 对象,设置订阅者的权限。

  {
      "reqPermissions": [{
          "name": "com.example.MyApplication.permission",
          "reason": "get right",
          "usedScene": {
             "ability": [
              ".MainAbility"
             ],
             "when": "inuse"
          }
      }, {
      ...
      }]
  }

  • 发布带权限的公共事件示例代码如下:

  Intent intent = new Intent();
  Operation operation = new Intent.OperationBuilder()
          .withAction("com.my.test")
          .build();
  intent.setOperation(operation);
  CommonEventData eventData = new CommonEventData(intent);
  CommonEventPublishInfo publishInfo = new CommonEventPublishInfo();
  String[] permissions = {"com.example.MyApplication.permission" };
  publishInfo.setSubscriberPermissions(permissions); // 设置权限
  try {   
       CommonEventManager.publishCommonEvent(eventData, publishInfo); 
  } catch (RemoteException e) {
       HiLog.info(LABEL, "publishCommoneEvent occur exception."); 
  }

发布有序的公共事件:构造 CommonEventPublishInfo 对象,通过 setOrdered(true) 指定公共事件属性为有序公共事件,也可以指定一个最后的公共事件接收者。

CommonEventSubscriber resultSubscriber = new MyCommonEventSubscriber();
CommonEventPublishInfo publishInfo = new CommonEventPublishInfo();
publishInfo.setOrdered(true); // 设置属性为有序公共事件
try {   
    CommonEventManager.publishCommonEvent(eventData, publishInfo, resultSubscriber); // 指定resultSubscriber为有序公共事件最后一个接收者。
} catch (RemoteException e) {
    HiLog.info(LABEL, "publishCommoneEvent occur exception."); 
}

发布粘性公共事件:构造 CommonEventPublishInfo 对象,通过 setSticky(true) 指定公共事件属性为粘性公共事件。

  1. 发布者首先在 config.json 中申请发布粘性公共事件所需的权限,各字段含义详见权限申请字段说明

   {
       "reqPermissions": [{
           "name": "ohos.permission.COMMONEVENT_STICKY",
           "reason": "get right",
           "usedScene": {
              "ability": [
               ".MainAbility"
              ],
              "when": "inuse"
           }
       }, {
       ...
       }]
   }

  1. 发布粘性公共事件。

   CommonEventPublishInfo publishInfo = new CommonEventPublishInfo();
   publishInfo.setSticky(true); // 设置属性为粘性公共事件
   try {   
       CommonEventManager.publishCommonEvent(eventData, publishInfo); 
   } catch (RemoteException e) {
       HiLog.info(LABEL, "publishCommoneEvent occur exception."); 
   }

订阅公共事件

  1. 创建 CommonEventSubscriber 派生类,在 onReceiveEvent() 回调函数中处理公共事件。

说明

此处不能执行耗时操作,否则会阻塞 UI 线程,产生用户点击没有反应等异常。

   class MyCommonEventSubscriber extends CommonEventSubscriber { 
       MyCommonEventSubscriber(CommonEventSubscribeInfo info) { 
           super(info);   
       }
       @Override 
       public void onReceiveEvent(CommonEventData commonEventData) {
       } 
   }

  1. 构造 MyCommonEventSubscriber 对象,调用 CommonEventManager.subscribeCommonEvent() 接口进行订阅。

   String event = "com.my.test";
   MatchingSkills matchingSkills = new MatchingSkills();
   filter.addEvent(event); // 自定义事件
   filter.addEvent(CommonEventSupport.COMMON_EVENT_SCREEN_ON); // 亮屏事件
   CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
   MyCommonEventSubscriber subscriber = new MyCommonEventSubscriber(subscribeInfo);
   try {
       CommonEventManager.subscribeCommonEvent(subscriber); 
   } catch (RemoteException e) {
       HiLog.info(LABEL, "subscribeCommonEvent occur exception."); 
   }

如果订阅拥有指定权限应用发布的公共事件,发布者需要在 config.json 中申请权限,各字段含义详见 权限申请字段说明

   "reqPermissions": [
       {
           "name": "ohos.abilitydemo.permission.PROVIDER",
           "reason": "get right",
           "usedScene": {
               "ability": ["com.huawei.hmi.ivi.systemsetting.MainAbility"],
               "when": "inuse"
           }
       }
   ]

如果订阅的公共事件是有序的,可以调用 setPriority()指定优先级。

   String event = "com.my.test";
   MatchingSkills matchingSkills = new MatchingSkills();
   matchingSkills.addEvent(event ); // 自定义事件

    
   CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
   subscribeInfo.setPriority(100); // 设置优先级,优先级取值范围[-1000,1000],值默认为0。
   MyCommonEventSubscriber subscriber = new MyCommonEventSubscriber(subscribeInfo);
   try {
        CommonEventManager.subscribeCommonEvent(subscriber); 
   } catch (RemoteException e) {
        HiLog.info(LABEL, "subscribeCommonEvent occur exception."); 
   }

  1. 针对在 onReceiveEvent 中不能执行耗时操作的限制,可以使用 CommonEventSubscriber 的 goAsyncCommonEvent() 来实现异步操作,函数返回后仍保持该公共事件活跃,且执行完成后必须调用 AsyncCommonEventResult .finishCommonEvent() 来结束。

   EventRunner runner = EventRunner.create(); //EventRunner 创建新线程,将耗时的操作放到新的线程上执行
   MyEventHandler myHandler = new MyEventHandler(runner); //MyEventHandler 为 EventHandler 的派生类,在不同线程间分发和处理事件和 Runnable 任务
   @Override
   public void onReceiveEvent(CommonEventData commonEventData){
       final AsyncCommonEventResult result = goAsyncCommonEvent();

    
       Runnable task = new Runnable() {
           @Override
           public void run() {
               ........         // 待执行的操作,由开发者定义
               result.finishCommonEvent(); // 调用finish结束异步操作
           }
       };
       myHandler.postTask(task);
   } 

退订公共事件

在 Ability的onStop() 中调用 CommonEventManager.unsubscribeCommonEvent() 方法来退订公共事件。调用后,之前订阅的所有公共事件均被退订。

try { 
    CommonEventManager.unsubscribeCommonEvent(subscriber);
 } catch (RemoteException e) {
    HiLog.info(LABEL, "unsubscribeCommonEvent occur exception.");
 }