#DAYU200体验官# 分布式家庭留言板实现 原创 精华

wx6253d0cc67f6c
发布于 2022-7-8 18:35
浏览
4收藏

#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。

#DAYU200体验官# 分布式家庭留言板实现-鸿蒙开发者社区

  • PageAbility是具备ArkUI实现的Ability,是用户具体可见并可以交互的Ability实例。
  • ServiceAbility也是Ability一种,但是没有UI,提供其他Ability调用自定义的服务,在后台运行。
  • DataAbility也是没有UI的Ability,提供其他Ability进行数据的增删查服务,在后台运行。
  • FormAbility是卡片Ability,是一种界面展示形式。

代码结构解读

本节内容只对核心代码进行讲解,对完整代码,我们已经上传,如有需要,请自行查阅。

整个工程的代码结构如下:
#DAYU200体验官# 分布式家庭留言板实现-鸿蒙开发者社区

  • 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
    • zh:
      • media:
        • icon.png
  • config.json:模块配置文件

主页面index.ets:

连接设备按键可以查看已连接的设备并进行连接,打开按键可以打开留言板页面。


#DAYU200体验官# 分布式家庭留言板实现-鸿蒙开发者社区

部分代码:

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:

页面如下图所示:

#DAYU200体验官# 分布式家庭留言板实现-鸿蒙开发者社区

点击“+”按钮,可以输入留言者的名字和内容,当我们点下发送时,两台设备会同时置顶新的消息,实现了家庭留言板的功能。

#DAYU200体验官# 分布式家庭留言板实现-鸿蒙开发者社区
部分代码:

  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,主要用到了一些技术:

  1. 实现了分布式调动启动远程FA
  2. 通过连接远程Service实现了多设备间通信
  3. 通过公共事件模块来实现应用内事件消息传递

分布式家庭留言板还有很多不足,后续还需要继续完善,如使用分布式数据库来保存和同步留言信息等。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
MessageBoard.zip 4.04M 56次下载
已于2022-7-8 18:35:35修改
2
收藏 4
回复
举报
回复
    相关推荐