前言
目前JS UI框架提供的事件发布订阅功能需要在API7版本上才能使用, 为满足开发需求, 我们在JAVA侧实现消息订阅分发逻辑, 通过JS调JAVA能力将接口暴露给JS侧, 以实现消息订阅发布能力。
效果展示
实现思路
1、定义消息数据
一个消息事件包含事件类型, 携带数据, 我们先定义一个JavaBean对象表示消息数据。
class Event {
private String type;
private String data;
}
2、定义接口
消息数据模型有了, 可以开始定义接口了。
消息订阅接口。
key
用于表示订阅者对象的标识. callback
是消息的回调接口, 我们希望订阅者只接收到自己关心的事件, 所以还需要增加一个参数subscribeEventTypes
表示关心的事件类型。
void subscribeEvent(key, subscribeEventTypes, callback)
取消订阅接口。
有订阅就会有取消, key
用于表示订阅者对象的唯一标识。
void unSubscribeEvent(key)
发布消息接口。
发布消息接口, type
表示消息类型, data
表示携带的数据。
void publishEvent(type, data)
3、JAVA侧逻辑
我们采用的是是PA调FA机制, 所以需要新建一个JAVA远程服务Ability, 目前有Server
和Internal
两种类型的服务Ability, 此处不需要考虑多进程和 生命周期问题, 所以这里使用Internal
Ability。
(1)先创建一个类EventInternalAbility, 调用setInternalAbilityHandler
接口实现JS侧请求处理接口, 处理三种请求。
public class EventInternalAbility extends AceInternalAbility {
private final ConcurrentHashMap<String, EventObserver> observers = new ConcurrentHashMap<>(10);
private EventInternalAbility() {
setInternalAbilityHandler(this::onRemoteRequest);
}
private boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
switch (code) {
case SUBSCRIBE: // 处理订阅消息请求
addObserver();
break;
case UNSUBSCRIBE: // 处理取消订阅消息请求
removeObserver();
break;
case PUBLISH_EVENT: // 处理消息分发
publishEvent();
break;
}
return true;
}
}
(2) 处理订阅消息请求, 我们需要在此函数下处理消息订阅的事件类型和订阅对象。
public class EventInternalAbility {
private void addObserver(MessageParcel data) {
JSON dataJson = new JSON(data.readString());
// 解析订阅者的标识
String key = dataJson.get("key");
// 解析订阅者关系的数据
List<String> subscribeEventTypes = dataJson.get("subscribeEventType");
// 添加订阅者到map队列中
observers.put(key, new EventObserver(subscribeEventTypes, data.readRemoteObject()));
}
}
(3) 处理取消订阅消息请求, 此逻辑比较简单, 将标识对应的订阅对象移除即可。
observers.remove(key)
(4)处理消息分发请求, 我们需要在此函数下完成消息数据解析和消息分发处理。
public class EventInternalAbility {
private void publishEvent(MessageParcel data) {
// 解析数据
JSON dataJson = new JSON(data.readString());
Stirng eventType = dataJson.get("type");
Stirng eventData = dataJson.get("data");
// 分发消息
observers.forEach((key, eventObserver) -> {
if (eventObserver.getSubscribeEventType().contains(eventType)) {
eventObserver.handlenEvent(eventType, eventData);
}
});
}
}
(5)到此我们JAVA侧的关键代码已经完成, 我们还需要在应用启动入口添加启动EventInternalAbility
服务。
public class EventInternalAbility {
private static final EventInternalAbility INSTANCE = new EventInternalAbility();
// 添加启动服务分发
public static void startServer() {
// 我们与已经在构造函数下实现了JS侧请求处理接口, 此处可为空
}
}
public class MyApplication extends AbilityPackage {
public void onInitialize() {
super.onInitialize();
// 在APP入口启动服务
EventInternalAbility.startServer();
}
}
4. JS侧逻辑
新建event-utils.js脚本文件, 实现上述定义的接口。
JS侧的代码比较简单, 主要将入参的数据透传给JAVA侧, 逻辑比较简单, 此处不再一一讲解。
将请求bundleName abilityName等参数抽为一个方法, 以减少重复代码。
const getParams = function (code) {
return {
messageCode: code,
// todo 此处修改为你项目的bundleName和abilityName
bundleName: 'com.chinasoftinc.event',
abilityName: 'com.chinasoftinc.event.event.EventInternalAbility',
abilityType: 1,
syncOption: 0,
data: code,
};
};
订阅消息:
subscribeEvent(key, subscribeEventTypes, eventCallback) {
let subInfoParams = getParams(Constants.SUBSCRIBE_INFO);
subInfoParams.data = {
"key": key,
"subscribeEventTypes": subscribeEventTypes,
}
FeatureAbility.subscribeAbilityEvent(params, eventCallback)
}
取消订阅:
unsubscribeEvent(key){
let params = getParams(Constants.UNSUBSCRIBE);
params.data = {
"key": key
}
FeatureAbility.unsubscribeAbilityEvent(params)
}
发布消息:
publishEvent(type, data){
let params = getParams(Constants.PUBLISH_EVENT);
params.data = {
"type": type,
"data": data,
}
return FeatureAbility.callAbility(params)
}
总结
至此关键代码逻辑已全部完成, 总体来说流程比较简单, 主要使用JS UI框架提供的FA调PA能力, 将JAVA侧的操作能力提供给JS侧使用。