#DAYU200体验官# 分布式家庭留言板实现 原创 精华
#DAYU200体验官# 分布式家庭留言板实现
介绍
本篇Codelab将会介绍如何创建一个简单方便的OpenHarmony家庭留言板,这个应用含有两个界面,分别是设备选择连接界面和编辑留言实时发送界面。可以由一台设备拉起另一台设备,每次发送留言内容,都会实时发送到另一台设备,两台设备同时置顶显示。效果如下:
搭建OpenHarmony开发环境
①开始前请参考工具准备 ,完成DevEco Studio的安装和开发环境配置。
②开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”),选择eTS语言开发。
③工程创建完成后,选择使用真机进行调测。
分布式组网
完成本篇Codelab我们还需要完成开发板的分布式组网,本示例DAYU200开发板为例,参照以下步骤进行:
1.硬件准备:准备两台烧录相同的版本系统的DAYU200开发板A、B。
2.两个开发板A、B配置在同一个WiFi网络之下。
3.打开设置–>WLAN–>点击右侧WiFi开关–>点击目标WiFi并输入密码。
4.将设备A、B设置为互相信任的设备
①找到系统应用“音乐”。
②设备A打开音乐,点击左下角带箭头的流转按钮,弹出列表框,在列表中会展示远端设备的id。
③选择远端设备B的id,另一台开发板(设备B)会弹出验证的选项框。
④设备B点击允许,设备B将会弹出随机PIN码,将设备B的PIN码输入到设备A的PIN码填入框中。
整体架构
OpenHarmony用户程序的开发本质上就是开发Ability。Ability框架使用FA模型, FA模型将Ability分为FA(Feature Ability)和PA(Particle Ability)两种类型。FA模型中Ability分为PageAbility、ServiceAbility、DataAbility、FormAbility几种类型,本篇Codelab只涉及到PageAbility和ServiceAbility。
- PageAbility是具备ArkUI实现的Ability,是用户具体可见并可以交互的Ability实例。
- ServiceAbility也是Ability一种,但是没有UI,提供其他Ability调用自定义的服务,在后台运行。
- DataAbility也是没有UI的Ability,提供其他Ability进行数据的增删查服务,在后台运行。
- FormAbility是卡片Ability,是一种界面展示形式。
代码结构解读
本节内容只对核心代码进行讲解,对完整代码,我们已经上传,如有需要,请自行查阅。
整个工程的代码结构如下:
-
ets:用于存放ets源码
-
MainAbility:应用/服务的入口
-
model:连接模型
- ConnectModel.ets:
- RemoteDeviceModel.ets:
-
pages:MainAbility包含的页面
- index.ets:pages列表中的第一个页面,即应用的首页入口。
- msgList.ets:消息列表页面
-
app.ets:承载Ability生命周期
-
-
ServiceAbility:服务
- service.ts:
-
-
resources:用于存放应用/服务所用到的资源文件,如图形、多媒体、字符串、布局文件等
- base:
- element:
- string.json
- media:
- icon.png
- element:
- zh:
- media:
- icon.png
- media:
- base:
-
config.json:模块配置文件
主页面index.ets:
连接设备按键可以查看已连接的设备并进行连接,打开按键可以打开留言板页面。
部分代码:
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Button('连接设备', { type: ButtonType.Normal, stateEffect: true })
.borderRadius(8)
.backgroundColor(0x317aff)
.width('60%')
.onClick(() => {
RegisterDeviceListCallback();
this.dialogController.open();
})
Button('打开', { type: ButtonType.Normal, stateEffect: true })
.borderRadius(8)
.backgroundColor(0x317aff)
.width('60%')
.margin(20)
.onClick(() => {
router.push({
uri: 'pages/msgList',
params: {}
});
})
}
.width('100%')
.height('100%')
}
订阅相关代码:
subscribeEvent() {
let self = this;
// 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作
var subscriber;
// 订阅者信息
var subscribeInfo = {
events: ["publish_change"],
priority: 100
};
// 设置有序公共事件的结果代码回调
function SetCodeCallBack() {
}
// 设置有序公共事件的结果数据回调
function SetDataCallBack() {
}
// 完成本次有序公共事件处理回调
function FinishCommonEventCallBack() {
}
// 订阅公共事件回调
function SubscribeCallBack(err, data) {
let msgData = data.data;
let code = data.code;
// 设置有序公共事件的结果代码
subscriber.setCode(code, SetCodeCallBack);
// 设置有序公共事件的结果数据
subscriber.setData(msgData, SetDataCallBack);
// 完成本次有序公共事件处理
subscriber.finishCommonEvent(FinishCommonEventCallBack)
// 处理接收到的数据data
// code = 1时
if (code == 2) {
featureAbility.terminateSelf()
}
prompt.showToast({
message: data.parameters.dataList
});
// connectModel.onDisconnectService();
}
//创建订阅者回调
function CreateSubscriberCallBack(err, data) {
subscriber = data;
//订阅公共事件
commonEvent.subscribe(subscriber, SubscribeCallBack);
}
//创建订阅者
commonEvent.createSubscriber(subscribeInfo, CreateSubscriberCallBack);
}
页面msgList.ets:
页面如下图所示:
点击“+”按钮,可以输入留言者的名字和内容,当我们点下发送时,两台设备会同时置顶新的消息,实现了家庭留言板的功能。
部分代码:
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
List() {
ForEach(this.messages, (item) => {
ListItem() {
Column() {
Text(item.name)
.fontSize('30px')
.fontColor('#463100')
Text(item.content)
.margin({ top: '20px', bottom: '20px' })
.fontSize('40px')
.fontColor('#463100')
Text(item.dateTime)
.width('100%')
.fontSize('25px')
.textAlign(TextAlign.End)
.fontColor('#999')
}
.padding('20px')
.margin('20px')
.alignItems(HorizontalAlign.Start)
.border({ width: '1px', style: BorderStyle.Solid, color: '#936800', radius: '10px', })
.backgroundColor('#fbeace')
.shadow({ radius: 5, color: '#eee', offsetX: 10, offsetY: 10 })
}
}, item => item.content)
}
.width('100%')
.padding({ top: '40px', right: '40px', left: '40px' })
.flexGrow(1)
Button('+', { type: ButtonType.Circle, stateEffect: true })
.borderRadius('72px')
.backgroundColor(0x317aff)
.margin('20px')
.fontSize('120px')
.onClick(() => {
this.dialogController.open()
})
}
.width('100%')
.height('100%')
}
订阅者事件相关:
subscribeEvent() {
let self = this;
// 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作
var subscriber;
// 订阅者信息
var subscribeInfo = {
events: ["publish_change"],
priority: 100
};
// 设置有序公共事件的结果代码回调
function SetCodeCallBack() {
}
// 设置有序公共事件的结果数据回调
function SetDataCallBack() {
}
// 完成本次有序公共事件处理回调
function FinishCommonEventCallBack() {
}
// 订阅公共事件回调
function SubscribeCallBack(err, data) {
let msgData = data.data;
let code = data.code;
// 设置有序公共事件的结果代码
subscriber.setCode(code, SetCodeCallBack);
// 设置有序公共事件的结果数据
subscriber.setData(msgData, SetDataCallBack);
// 完成本次有序公共事件处理
subscriber.finishCommonEvent(FinishCommonEventCallBack)
// 处理接收到的数据data
if (code == 2) {
featureAbility.terminateSelf()
}
else {
self.messages.unshift(JSON.parse(data.parameters.dataList))
}
}
//创建订阅者回调
function CreateSubscriberCallBack(err, data) {
subscriber = data;
//订阅公共事件
commonEvent.subscribe(subscriber, SubscribeCallBack);
}
//创建订阅者
commonEvent.createSubscriber(subscribeInfo, CreateSubscriberCallBack);
}
ConnectModel.ets关键代码:
import prompt from '@system.prompt';
import featureAbility from '@ohos.ability.featureAbility';
import rpc from "@ohos.rpc";
export default class ConnectModel {
connectedAbility;
mRemote;
constructor() {
}
// 连接远端Service
async onConnectRemoteService(deviceId) {
var that = this
// 连接成功的回调
async function onConnectCallback(element, remote) {...}
// Service异常死亡的回调
function onDisconnectCallback(element) {...}
// 连接失败的回调
function onFailedCallback(code) {...}
// 连接成功后发送消息
// 传入code
async sendMessageToRemoteService(dataList, code) {...}
// 断开连接
async onDisconnectService() {...}
}
RemoteDeviceModel.ets关键代码:
//创建设备对象类
import deviceManager from '@ohos.distributedHardware.deviceManager';
var SUBSCRIBE_ID = 100;
export default class RemoteDeviceModel {
deviceList = [];
discoverList = [];
localDeviceId = '';
callback;
authCallback = null;
#deviceManager;
constructor() {
}
//注册设备回调方法
registerDeviceListCallback(callback){...}
//注册设备回调子方法
registerDeviceListCallback_(callback){...}
//身份验证
authDevice(deviceId, callback){}
}
总结:
根据查阅官方的文档和Demo,主要用到了一些技术:
- 实现了分布式调动启动远程FA
- 通过连接远程Service实现了多设备间通信
- 通过公共事件模块来实现应用内事件消息传递
分布式家庭留言板还有很多不足,后续还需要继续完善,如使用分布式数据库来保存和同步留言信息等。