OpenHarmony 使用FA調PA能力實現JS消息訂閱功能
前言
目前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側使用。