HarmonyOS之公共事件的发布、订阅与退订

一、简介
① 概念
  • HarmonyOS 通过 CES(Common Event Service,公共事件服务)为应用程序提供订阅、发布、退订公共事件的能力,通过 ANS(Advanced Notification Service,即通知增强服务)系统服务来为应用程序提供发布通知的能力。
  • 公共事件可分为系统公共事件和自定义公共事件:
    • 系统公共事件:系统将收集到的事件信息,根据系统策略发送给订阅该事件的用户程序。 公共事件包括:终端设备用户可感知的亮灭屏事件,以及系统关键服务发布的系统事件(例如:USB 插拔,网络连接,系统升级)等;
    • 自定义公共事件:应用自定义一些公共事件用来处理业务逻辑。
  • 应用如果需要接收公共事件,需要订阅相应的事件。
② 约束与限制
  • 目前公共事件仅支持动态订阅,部分系统事件需要具有指定的权限。
  • 目前公共事件订阅不支持多用户。
  • ThreadMode 表示线程模型,目前仅支持 HANDLER 模式,即在当前 UI 线程上执行回调函数。
  • deviceId 用来指定订阅本地公共事件还是远端公共事件。deviceId 为 null、空字符串或本地设备 deviceId 时,表示订阅本地公共事件,否则表示订阅远端公共事件。
③ 应用场景
  • 每个应用都可以订阅自己感兴趣的公共事件,订阅成功后且公共事件发布后,系统会把其发送给应用,这些公共事件可能来自系统、其它应用和应用自身。
  • HarmonyOS 提供了一套完整的 API,支持用户订阅、发布和接收公共事件。发布公共事件需要借助 CommonEventData 对象,接收公共事件需要继承 CommonEventSubscriber 类并实现 onReceiveEvent 回调函数。
三、公共事件的 API 说明
  • 公共事件相关基础类包含 CommonEventData、CommonEventPublishInfo、CommonEventSubscribeInfo、CommonEventSubscriber 和 CommonEventManager。基础类之间的关系如下图所示:

HarmonyOS之公共事件的发布、订阅与退订_第1张图片

① CommonEventData
  • CommonEventData 封装公共事件相关信息,用于在发布、分发和接收时处理数据。
  • 在构造 CommonEventData 对象时,相关参数需要注意以下事项:
    • code 为有序公共事件的结果码,data 为有序公共事件的结果数据,仅用于有序公共事件场景。
    • intent 不允许为空,否则发布公共事件失败。
  • CommonEventData 主要 API:
接口名 描述
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() 方法设置, 发布粘性公共事件需要申请如下权限:
	"reqPermissions": [
	  {
	    "name": "ohos.permission.COMMONEVENT_STICKY",
	    "reason": "Obtain the required permission",
	    "usedScene": {
	      "ability": [
	        ".MainAbility"
	      ],
	      "when": "inuse"
	    }
	  },
	  {
	    ...
	  }
	]
  • CommonEventPublishInfo 主要接口:
接口名 描述
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 主要接口:
接口名 描述
CommonEventSubscribeInfo(MatchingSkills matchingSkills) 创建公共事件订阅器指定matchingSkills
CommonEventSubscribeInfo(CommonEventSubscribeInfo) 拷贝公共事件订阅器对象
setPriority(int priority) 设置优先级,用于有序公共事件
setThreadMode(ThreadMode threadMode) 指定订阅者的回调函数运行在哪个线程上
setPermission(String permission) 设置发布者必须具备的权限
setDeviceId(String deviceId) 指定订阅哪台设备的公共事件
④ CommonEventSubscriber
  • CommonEventSubscriber 封装公共事件订阅者及相关参数:
    • CommonEventSubscriber.AsyncCommonEventResult 类处理有序公共事件异步执行;
    • 目前只能通过调用 CommonEventManager 的 subscribeCommonEvent() 进行订阅。
  • CommonEventSubscriber 主要接口:
接口名 描述
CommonEventSubscriber(CommonEventSubscribeInfo subscribeInfo) 构造公共事件订阅者实例
onReceiveEvent(CommonEventData data) 由开发者实现, 在接收到公共事件时被调用
AsyncCommonEventResult goAsyncCommonEvent() 设置有序公共事件异步执行
setCodeAndData(int code, String data) 设置有序公共事件的异步结果
setData(String data) 设置有序公共事件的异步结果数据
setCode(int code) 设置有序公共事件的异步结果码
getData() 获取有序公共事件的异步结果数据
getCode() 获取有序公共事件的异步结果码
abortCommonEvent() 取消当前的公共事件,仅对有序公共事件有效,取消后,公共事件不再向下一个订阅者传递
getAbortCommonEvent() 获取当前有序公共事件是否取消的状态
clearAbortCommonEvent() 清除当前有序公共事件abort状态
isOrderedCommonEvent() 查询当前公共事件的是否为有序公共事件
isStickyCommonEvent() 查询当前公共事件是否为粘性公共事件
⑤ CommonEventManager
  • CommonEventManager 是为应用提供订阅、退订和发布公共事件的静态接口类。
  • CommonEventManager 主要接口:
方法 描述
publishCommonEvent(CommonEventData eventData) 发布公共事件
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); 
	    HiLog.info(LABEL_LOG, "Publish succeeded"); 
	} catch (RemoteException e) {
	    HiLog.error(LABEL_LOG, "Exception occurred during publishCommonEvent invocation."); 
	}
② 发布带权限的公共事件
  • 构造 CommonEventPublishInfo 对象,设置订阅者的权限。
  • 订阅者在 config.json 中申请所需的权限:
	"reqPermissions": [
	  {
	    "name": "com.example.MyApplication.permission",
	    "reason": "Obtain the required permission",
	    "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); 
	    HiLog.info(LABEL_LOG, "Publish succeeded"); 
	} catch (RemoteException e) {
	    HiLog.error(LABEL_LOG, "Exception occurred during publishCommonEvent invocation."); 
	}
③ 发布有序的公共事件
  • 构造 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.error(LABEL_LOG, "Exception occurred during publishCommonEvent invocation."); 
	}
④ 发布粘性的公共事件
  • 构造 CommonEventPublishInfo 对象,通过 setSticky(true) 指定公共事件属性为粘性公共事件。
  • 发布者首先在 config.json 中申请发布粘性公共事件所需的权限:
	{
	    "reqPermissions": [{
	        "name": "ohos.permission.COMMONEVENT_STICKY",
	        "reason": "Obtain the required permission",
	        "usedScene": {
	           "ability": [
	            ".MainAbility"
	           ],
	           "when": "inuse"
	        }
	    }, {
	    ...
	    }]
	}
  • 发布粘性公共事件:
	CommonEventPublishInfo publishInfo = new CommonEventPublishInfo();
	publishInfo.setSticky(true); // 设置属性为粘性公共事件
	try {   
	    CommonEventManager.publishCommonEvent(eventData, publishInfo); 
	} catch (RemoteException e) {
	    HiLog.error(LABEL, "Exception occurred during publishCommonEvent invocation."); 
	}
五、订阅公共事件
  • 创建 CommonEventSubscriber 派生类,在 onReceiveEvent() 回调函数中处理公共事件:
	class MyCommonEventSubscriber extends CommonEventSubscriber { 
	    MyCommonEventSubscriber(CommonEventSubscribeInfo info) { 
	        super(info);   
	    }
	    @Override 
	    public void onReceiveEvent(CommonEventData commonEventData) {
	    } 
	}
  • 构造 MyCommonEventSubscriber 对象,调用 CommonEventManager.subscribeCommonEvent() 接口进行订阅:
	String event = "com.my.test";
	MatchingSkills matchingSkills = new MatchingSkills();
	matchingSkills.addEvent(event); // 自定义事件
	matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_SCREEN_ON); // 亮屏事件
	CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
	MyCommonEventSubscriber subscriber = new MyCommonEventSubscriber(subscribeInfo);
	try {
	    CommonEventManager.subscribeCommonEvent(subscriber); 
	} catch (RemoteException e) {
	    HiLog.error(LABEL, "Exception occurred during subscribeCommonEvent invocation."); 
	}
  • 如果订阅拥有指定权限应用发布的公共事件,发布者需要在 config.json 中申请权限:
	"reqPermissions": [
	    {
	        "name": "ohos.abilitydemo.permission.PROVIDER",
	        "reason": "Obtain the required permission",
	        "usedScene": {
	            "ability": ["com.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.error(LABEL, "Exception occurred during subscribeCommonEvent invocation."); 
	}
  • 针对在 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.error(LABEL, "Exception occurred during unsubscribeCommonEvent invocation.");
	 }

你可能感兴趣的:(HarmonyOS,公共事件的概念和使用限制,公共事件的应用场景和API说明,如何发布公共事件?,如何订阅公共事件?,如何退订公共事件?)