作者: 餘香鑫
前言
目前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.
3.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;
}
}
3.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.3 處理取消訂閱消息請求, 此邏輯比較簡單, 将辨別對應的訂閱對象移除即可
observers.remove(key)
3.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);
}
});
}
}
3.5 到此我們JAVA側的關鍵代碼已經完成, 我們還需要在應用啟動入口添加啟動
EventInternalAbility
服務
public class EventInternalAbility {
private static final EventInternalAbility INSTANCE = new EventInternalAbility();
// 添加啟動服務分發
public static void startServer() {
// 我們與已經在構造函數下實作了JS側請求處理接口, 此處可為空
}
}
public class MyApplication extends AbilityPackage {
@Override
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側使用.
完整項目代碼可以前往Gitee檢視
更多原創内容請關注:中軟國際 HarmonyOS 技術團隊
入門到精通、技巧到案例,系統化分享HarmonyOS開發技術,歡迎投稿和訂閱,讓我們一起攜手前行共建鴻蒙生态。