HarmonyOS 基础技术赋能之 公共事件(CommonEvent)开发 原创 精华
引言
在HarmonyOS通过CES(Common Event Service,公共事件服务)为应用程序提供订阅、发布、退订公共事件的能力。
公共事件可分为系统公共事件和自定义公共事件。
系统公共事件:系统将收集到的事件信息,根据系统策略发送给订阅该事件的用户程序。 公共事件包括:终端设备用户可感知的亮灭屏事件,以及系统关键服务发布的系统事件(例如:USB插拔,网络连接,系统升级)等。
自定义公共事件:应用自定义一些公共事件用来处理业务逻辑。
场景介绍
每个应用都可以订阅自己感兴趣的公共事件,订阅成功后且公共事件发布后,系统会把其发送给应用。这些公共事件可能来自系统、其他应用和应用自身。HarmonyOS提供了一套完整的API,支持用户订阅、发布和接收公共事件。发布公共事件需要借助CommonEventData对象,接收公共事件需要继承CommonEventSubscriber类并实现onReceiveEvent回调函数。
开发者可以发布四种公共事件:无序的公共事件、带权限的公共事件、有序的公共事件、粘性的公共事件。
本文主讲无序的公共事件,其他类型事件,可参考华为官方开发文档学习。
指南
1.发布公共事件:
try {
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withAction(“my.action”)//自定义字符串类型的action
.build();
intent.setOperation(operation);
intent.setParam("result","commonEventData");
intent.setParam("isCommonEvent",true);
CommonEventData eventData = new CommonEventData(intent);
CommonEventManager.publishCommonEvent(eventData);
LogUtils.info(TAG,"PublishCommonEvent SUCCESS");
} catch (RemoteException e) {
LogUtils.error(TAG,"Exception occurred during publishCommonEvent invocation.");
}
2. 订阅公共事件
1)创建CommonEventSubscriber派生类,在onReceiveEvent()回调函数中处理公共事件。
private class MyCommonEventSubscriber extends CommonEventSubscriber {
MyCommonEventSubscriber(CommonEventSubscribeInfo info) {
super(info);
}
@Override
public void onReceiveEvent(CommonEventData commonEventData) {
}
2)构造MyCommonEventSubscriber对象,调用CommonEventManager. subscribeCommonEvent()接口进行订阅。
MatchingSkills matchingSkills = new MatchingSkills();
//添加自定义的ation
matchingSkills.addEvent(ACTION);
matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_BOOT_COMPLETED); // 开机完成事件
matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_CHARGING); // 正在充电事件
CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
subscriber = new MyCommonEventSubscriber(subscribeInfo);
try {
CommonEventManager.subscribeCommonEvent(subscriber);
LogUtils.info(TAG,"SubscribeCommonEvent SUCCESS");
} catch (RemoteException e) {
LogUtils.error(TAG,"Exception occurred during subscribeCommonEvent invocation.");
}
3)针对在onReceiveEvent中不能执行耗时操作的限制,可以使用CommonEventSubscriber的goAsyncCommonEvent()来实现异步操作,函数返回后仍保持该公共事件活跃,且执行完成后必须调用。
// EventRunner创建新线程,将耗时的操作放到新的线程上执行
private EventRunner eventRunner=EventRunner.create();
// MyEventHandler为EventHandler的派生类,在不同线程间分发和处理事件和Runnable任务
private MyEventHandle myEventHandle=new MyEventHandle(eventRunner);
private class MyCommonEventSubscriber extends CommonEventSubscriber {
MyCommonEventSubscriber(CommonEventSubscribeInfo info) {
super(info);
}
@Override
public void onReceiveEvent(CommonEventData commonEventData) {
//以下为如果有耗时操作时,执行的代码
final AsyncCommonEventResult result = goAsyncCommonEvent();
Runnable runnable=new Runnable() {
@Override
public void run() {
// 待执行的操作,由开发者定义
myEventHandle.sendEvent(100);
result.finishCommonEvent(); // 调用finish结束异步操作
}
};
myEventHandle.postTask(runnable);
}
}
private class MyEventHandle extends EventHandler{
public MyEventHandle(EventRunner runner) throws IllegalArgumentException {
super(runner);
}
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
//处理事件,由开发者撰写
int evnetID=event.eventId;
LogUtils.info(TAG,"evnetID:"+evnetID);
}
}
3. 退订公共事件:
//在Ability的onStop()中调用CommonEventManager.unsubscribeCommonEvent()方法来退订公共事件。调用后,之前订阅的所有公共事件均被退订。
@Override
protected void onStop() {
super.onStop();
try {
CommonEventManager.unsubscribeCommonEvent(subscriber);
LogUtils.info(TAG, "unsubscribeCommonEvent success.");
} catch (RemoteException e) {
LogUtils.error(TAG, "Exception occurred during unsubscribeCommonEvent invocation.");
}
}
实现效果
1.启动APP时,如下图:
2. 先点击“订阅公共事件”,后点击“发布无序公共事件”。打印的log:
09-02 10:31:07.693 10390-10390/com.zel.commoneventdemo I 00000/LogUtil: MainAbilitySlice: SubscribeCommonEvent SUCCESS
09-02 10:31:09.795 10390-10390/com.zel.commoneventdemo I 00000/LogUtil: MainAbilitySlice: PublishCommonEvent SUCCESS
09-02 10:31:09.798 10390-10390/com.zel.commoneventdemo I 00000/LogUtil: MainAbilitySlice: action:action.send.message/result:commonEventData/isCommonEvent:true
09-02 10:31:09.799 10390-12455/com.zel.commoneventdemo I 00000/LogUtil: MainAbilitySlice: evnetID:100
附上源码
1.MainAbilitySlice
public class MainAbilitySlice extends AbilitySlice implements ClickedListener {
private String TAG="MainAbilitySlice";
private MyCommonEventSubscriber subscriber;
private static final String ACTION="action.send.message";
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
Button btPublisher=(Button)findComponentById(ResourceTable.Id_btPublisher);
Button btSubscriber=(Button)findComponentById(ResourceTable.Id_btSubscriber);
btPublisher.setClickedListener(this);
btSubscriber.setClickedListener(this);
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
@Override
public void onClick(Component component) {
switch (component.getId()){
case ResourceTable.Id_btPublisher:
try {
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withAction(ACTION)
.build();
intent.setOperation(operation);
intent.setParam("result","commonEventData");
intent.setParam("isCommonEvent",true);
CommonEventData eventData = new CommonEventData(intent);
CommonEventManager.publishCommonEvent(eventData);
LogUtils.info(TAG,"PublishCommonEvent SUCCESS");
} catch (RemoteException e) {
LogUtils.error(TAG,"Exception occurred during publishCommonEvent invocation.");
}
break;
case ResourceTable.Id_btSubscriber:
MatchingSkills matchingSkills = new MatchingSkills();
//添加自定义的ation
matchingSkills.addEvent(ACTION);//自定义事件
matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_BOOT_COMPLETED); // 开机完成事件
matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_CHARGING); // 正在充电事件
CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
subscriber = new MyCommonEventSubscriber(subscribeInfo);
try {
CommonEventManager.subscribeCommonEvent(subscriber);
LogUtils.info(TAG,"SubscribeCommonEvent SUCCESS");
} catch (RemoteException e) {
LogUtils.error(TAG,"Exception occurred during subscribeCommonEvent invocation.");
}
break;
}
}
//// EventRunner创建新线程,将耗时的操作放到新的线程上执行
private EventRunner eventRunner=EventRunner.create();
// MyEventHandler为EventHandler的派生类,在不同线程间分发和处理事件和Runnable任务
private MyEventHandle myEventHandle=new MyEventHandle(eventRunner);
private class MyCommonEventSubscriber extends CommonEventSubscriber {
MyCommonEventSubscriber(CommonEventSubscribeInfo info) {
super(info);
}
/**
* 针对在onReceiveEvent中不能执行耗时操作的限制,可以使用CommonEventSubscriber的goAsyncCommonEvent()来实现异步操作,
* 函数返回后仍保持该公共事件活跃,且执行完成后必须调用AsyncCommonEventResult.finishCommonEvent()来结束。
* @param commonEventData
*/
@Override
public void onReceiveEvent(CommonEventData commonEventData) {
//非执行耗时操作,以下代码即可
Intent intent=commonEventData.getIntent();
String action= intent.getAction();
switch (action){
//自定义事件
case ACTION:
String result=intent.getStringParam("result");
boolean isCommonEventData=intent.getBooleanParam("isCommonEvent",false);
LogUtils.info(TAG,"action:"+action+"/result:"+result+"/isCommonEvent:"+isCommonEventData);
break;
// 开机完成事件
case CommonEventSupport.COMMON_EVENT_BOOT_COMPLETED:
LogUtils.info(TAG,"action:"+action);
break;
// 正在充电事件
case CommonEventSupport.COMMON_EVENT_CHARGING:
LogUtils.info(TAG,"action:"+action);
break;
}
//以下为如果有耗时操作时,选择执行的代码
final AsyncCommonEventResult result = goAsyncCommonEvent();
Runnable runnable=new Runnable() {
@Override
public void run() {
// 待执行的操作,由开发者定义
myEventHandle.sendEvent(100);
result.finishCommonEvent(); // 调用finish结束异步操作
}
};
myEventHandle.postTask(runnable);
}
}
private class MyEventHandle extends EventHandler{
public MyEventHandle(EventRunner runner) throws IllegalArgumentException {
super(runner);
}
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
//处理事件,由开发者撰写
int evnetID=event.eventId;
LogUtils.info(TAG,"evnetID:"+evnetID);
}
}
@Override
protected void onStop() {
super.onStop();
try {
CommonEventManager.unsubscribeCommonEvent(subscriber);
LogUtils.info(TAG, "unsubscribeCommonEvent success.");
} catch (RemoteException e) {
LogUtils.error(TAG, "Exception occurred during unsubscribeCommonEvent invocation.");
}
}
}
2.LogUtils
public class LogUtils {
private static final String TAG_LOG = "LogUtil";
private static final HiLogLabel LABEL_LOG = new HiLogLabel(0, 0, LogUtils.TAG_LOG);
private static final String LOG_FORMAT = "%{public}s: %{public}s";
private LogUtils() { }
/**
* Print debug log
*
* @param tag log tag
* @param msg log message
*/
public static void debug(String tag, String msg) {
HiLog.debug(LABEL_LOG, LOG_FORMAT, tag, msg);
}
/**
* Print info log
*
* @param tag log tag
* @param msg log message
*/
public static void info(String tag, String msg) {
HiLog.info(LABEL_LOG, LOG_FORMAT, tag, msg);
}
/**
* Print warn log
*
* @param tag log tag
* @param msg log message
*/
public static void warn(String tag, String msg) {
HiLog.warn(LABEL_LOG, LOG_FORMAT, tag, msg);
}
/**
* Print error log
*
* @param tag log tag
* @param msg log message
*/
public static void error(String tag, String msg) {
HiLog.error(LABEL_LOG, LOG_FORMAT, tag, msg);
}
}
3. xml 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:orientation="vertical"
ohos:width="match_parent">
<DirectionalLayout
ohos:height="match_content"
ohos:width="match_parent"
ohos:left_margin="20vp"
ohos:right_margin="20vp"
ohos:top_margin="50vp"
ohos:orientation="vertical">
<Button
ohos:id="$+id:btPublisher"
ohos:height="match_content"
ohos:width="match_content"
ohos:text_size="22vp"
ohos:text_color="#ffffff"
ohos:text="发布无序公共事件"
ohos:padding="20vp"
ohos:background_element="#00ffff"/>
<Button
ohos:id="$+id:btSubscriber"
ohos:height="match_content"
ohos:width="match_content"
ohos:text_size="22vp"
ohos:text_color="#ffffff"
ohos:text="订阅公共事件"
ohos:padding="20vp"
ohos:top_margin="30vp"
ohos:background_element="#00ffff"/>
</DirectionalLayout>
</DirectionalLayout>
更多原创内容请关注:软通动力HarmonyOS学院
张老师这段时间很高产
张老师很勤快