0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于鸿蒙分布式数据服务开发的聊天室应用

OpenHarmony技术社区 来源:HarmonyOS技术社区 作者:梁青松 2021-12-03 10:35 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

之前给大家介绍过《HarmonyOS 分布式之仿抖音应用》,此次给大家介绍一下基于鸿蒙分布式数据服务开发的聊天室应用,模拟现实中的聊天室对话,可以与小伙伴们互动、分享自己的故事给小伙伴。

主要知识点

分布式数据服务

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/database-mdds-guidelines-0000000000030122

官方介绍:分布式数据服务主要实现用户设备中应用程序的数据内容的分布式同步。

当设备 1 上的应用 A 在分布式数据库中增、删、改数据后,设备 2 上的应用 A 也可以获取到该数据库变化,总结一句话:多个设备共用一个数据库。

主页代码

没有特别复杂的逻辑,主要是分布式数据服务的使用,关键地方都有注释。
importcom.ldd.myapp.bean.ChatDataBean;
importcom.ldd.myapp.provider.ChatProvider;
importcom.ldd.myapp.util.Tools;
importohos.aafwk.ability.AbilitySlice;
importohos.aafwk.content.Intent;
importohos.agp.components.Button;
importohos.agp.components.ListContainer;
importohos.agp.components.TextField;
importohos.app.Context;
importohos.bundle.IBundleManager;
importohos.data.distributed.common.*;
importohos.data.distributed.user.SingleKvStore;
importohos.utils.zson.ZSONArray;
importohos.utils.zson.ZSONObject;

importjava.util.ArrayList;
importjava.util.List;

importstaticohos.security.SystemPermission.DISTRIBUTED_DATASYNC;

/**
*主页
*/
publicclassMainAbilitySliceextendsAbilitySlice{
privateContextmContext;
//聊天列表
privateListContainerlcList;
//聊天数据
privatefinalListlistData=newArrayList<>();
//聊天数据适配器
privateChatProviderchatProvider;
//输入框
privateTextFieldtfContent;
//发送按钮
privateButtonbtnSend;

//分布式数据库管理器
privateKvManagerkvManager;
//分布式数据库
privateSingleKvStoresingleKvStore;
//数据库名称
privatestaticfinalStringSTORE_NAME="ChatStore";
//存入的列表数据key
privatestaticfinalStringKEY_DATA="key_data";
//存入的头像索引
privatestaticfinalStringKEY_PIC_INDEX="key_pic_index";
privateintpicIndex=0;

@Override
publicvoidonStart(Intentintent){
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
mContext=this;
requestPermission();
initComponent();
initDatabase();
}

/**
*请求分布式权限
*/
privatevoidrequestPermission(){
if(verifySelfPermission(DISTRIBUTED_DATASYNC)!=IBundleManager.PERMISSION_GRANTED){
if(canRequestPermission(DISTRIBUTED_DATASYNC)){
requestPermissionsFromUser(newString[]{DISTRIBUTED_DATASYNC},0);
}
}
}

/**
*初始化组件
*/
privatevoidinitComponent(){
lcList=(ListContainer)findComponentById(ResourceTable.Id_lc_list);
tfContent=(TextField)findComponentById(ResourceTable.Id_tf_content);
tfContent.setAdjustInputPanel(true);
btnSend=(Button)findComponentById(ResourceTable.Id_btn_send);
btnSend.setEnabled(false);

//初始化适配器
chatProvider=newChatProvider(mContext,listData);
lcList.setItemProvider(chatProvider);

//输入框内容变化监听
tfContent.addTextObserver((text,start,before,count)->{
btnSend.setEnabled(text.length()!=0);
});
//点击发送按钮
btnSend.setClickedListener(component->{
Stringcontent=tfContent.getText().trim();
listData.add(newChatDataBean(Tools.getDeviceId(mContext),picIndex,content));
//存入数据库中
singleKvStore.putString(KEY_DATA,ZSONObject.toZSONString(listData));

//清空输入框
tfContent.setText("");
});
}

/**
*初始化分布式数据库
*/
privatevoidinitDatabase(){
//创建分布式数据库管理器
kvManager=KvManagerFactory.getInstance().createKvManager(newKvManagerConfig(this));

//数据库配置
Optionsoptions=newOptions();
options.setCreateIfMissing(true)//设置数据库不存在时是否创建
.setEncrypt(false)//设置数据库是否加密
.setKvStoreType(KvStoreType.SINGLE_VERSION);//数据库类型
//创建分布式数据库
singleKvStore=kvManager.getKvStore(options,STORE_NAME);
//监听数据库数据改变
singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,newKvStoreObserver(){
@Override
publicvoidonChange(ChangeNotificationchangeNotification){
ListinsertEntries=changeNotification.getInsertEntries();
ListupdateEntries=changeNotification.getUpdateEntries();

//第一次存入数据,获取insertEntries
if(insertEntries.size()>0){
for(Entryentry:insertEntries){
if(KEY_DATA.equals(entry.getKey())){
//回调为非UI线程,需要在UI线程更新UI
getUITaskDispatcher().syncDispatch(()->{
listData.clear();
listData.addAll(ZSONArray.stringToClassList(entry.getValue().getString(),ChatDataBean.class));
chatProvider.notifyDataChanged();
lcList.scrollTo(listData.size()-1);
});
}
}
}elseif(updateEntries.size()>0){
for(Entryentry:updateEntries){
if(KEY_DATA.equals(entry.getKey())){
//回调为非UI线程,需要在UI线程更新UI
getUITaskDispatcher().syncDispatch(()->{
listData.clear();
listData.addAll(ZSONArray.stringToClassList(entry.getValue().getString(),ChatDataBean.class));
chatProvider.notifyDataChanged();
lcList.scrollTo(listData.size()-1);
});
}
}
}
}
});

try{
picIndex=singleKvStore.getInt(KEY_PIC_INDEX);
singleKvStore.putInt(KEY_PIC_INDEX,picIndex+1);
}catch(KvStoreExceptione){
e.printStackTrace();
//没有找到,首次进入
if(e.getKvStoreErrorCode()==KvStoreErrorCode.KEY_NOT_FOUND){
picIndex=0;
singleKvStore.putInt(KEY_PIC_INDEX,picIndex+1);
}
}
}

@Override
protectedvoidonStop(){
super.onStop();
kvManager.closeKvStore(singleKvStore);
}
}

简单案例

config.json 配置:
"reqPermissions":[
{
"reason":"多设备协同",
"name":"ohos.permission.DISTRIBUTED_DATASYNC",
"usedScene":{
"ability":[
"MainAbility"
],
"when":"always"
}
},
{
"name":"ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
},
{
"name":"ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
},
{
"name":"ohos.permission.GET_BUNDLE_INFO"
}
]

布局页面:

<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">

<Text
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="数据:0"
ohos:text_size="15fp"/>

<Button
ohos:margin="20vp"
ohos:id="$+id:button"
ohos:height="match_content"
ohos:width="match_parent"
ohos:background_element="$graphic:button_bg"
ohos:padding="10vp"
ohos:text="点击+1"
ohos:text_color="white"
ohos:text_size="15fp"/>

DirectionalLayout>
MainAbilitySlice 代码:
importohos.aafwk.ability.AbilitySlice;
importohos.aafwk.content.Intent;
importohos.agp.components.Button;
importohos.agp.components.ListContainer;
importohos.agp.components.Text;
importohos.agp.components.TextField;
importohos.bundle.IBundleManager;
importohos.data.distributed.common.*;
importohos.data.distributed.user.SingleKvStore;
importohos.utils.zson.ZSONArray;

importjava.util.List;

importstaticohos.security.SystemPermission.DISTRIBUTED_DATASYNC;

publicclassMainAbilitySliceextendsAbilitySlice{
//显示数据
privateTexttext;
//分布式数据库管理器
privateKvManagerkvManager;
//分布式数据库
privateSingleKvStoresingleKvStore;
//数据库名称
privatestaticfinalStringSTORE_NAME="MyStore";
//存入的数据key
privatestaticfinalStringKEY_COUNT="key_count";

@Override
publicvoidonStart(Intentintent){
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
requestPermission();
initDatabase();
initComponent();
}

/**
*请求分布式权限
*/
privatevoidrequestPermission(){
if(verifySelfPermission(DISTRIBUTED_DATASYNC)!=IBundleManager.PERMISSION_GRANTED){
if(canRequestPermission(DISTRIBUTED_DATASYNC)){
requestPermissionsFromUser(newString[]{DISTRIBUTED_DATASYNC},0);
}
}
}

/**
*初始化分布式数据库
*/
privatevoidinitDatabase(){
//创建分布式数据库管理器
kvManager=KvManagerFactory.getInstance().createKvManager(newKvManagerConfig(this));

//数据库配置
Optionsoptions=newOptions();
options.setCreateIfMissing(true)//设置数据库不存在时是否创建
.setEncrypt(false)//设置数据库是否加密
.setKvStoreType(KvStoreType.SINGLE_VERSION);//数据库类型
//创建分布式数据库
singleKvStore=kvManager.getKvStore(options,STORE_NAME);
//监听数据库数据改变
singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,newKvStoreObserver(){
@Override
publicvoidonChange(ChangeNotificationchangeNotification){
ListinsertEntries=changeNotification.getInsertEntries();
ListupdateEntries=changeNotification.getUpdateEntries();

//第一次存入数据,获取insertEntries
if(insertEntries.size()>0){
for(Entryentry:insertEntries){
if(KEY_COUNT.equals(entry.getKey())){
//回调为非UI线程,需要在UI线程更新UI
getUITaskDispatcher().syncDispatch(()->{
intcount=entry.getValue().getInt();
text.setText("数据:"+count);
});
}
}
}elseif(updateEntries.size()>0){
for(Entryentry:updateEntries){
if(KEY_COUNT.equals(entry.getKey())){
//回调为非UI线程,需要在UI线程更新UI
getUITaskDispatcher().syncDispatch(()->{
intcount=entry.getValue().getInt();
text.setText("数据:"+count);
});
}
}
}
}
});

}

/**
*初始化组件
*/
privatevoidinitComponent(){
text=(Text)findComponentById(ResourceTable.Id_text);
Buttonbutton=(Button)findComponentById(ResourceTable.Id_button);

//点击事件
button.setClickedListener(component->{
try{
intcount=singleKvStore.getInt(KEY_COUNT);
singleKvStore.putInt(KEY_COUNT,count+1);
}catch(KvStoreExceptione){
e.printStackTrace();
//没有找到,首次进入
if(e.getKvStoreErrorCode()==KvStoreErrorCode.KEY_NOT_FOUND){
intcount=0;
singleKvStore.putInt(KEY_COUNT,count+1);
}
}
});
}
}
注释比较详细,主要注意 2 个点:
  • 获取数据时加入 try catch 块,处理 key 未找到的情况。

  • 数据库数据改变监听回调是非 UI 线程,如果更新 UI 必须切换到 UI 线程。

以上简单案例就是让你快速掌握分布式数据服务:多个设备相同的应用之间使用同一个数据库。 项目地址(需要登录才能看到演示图):
https://gitee.com/liangdidi/DistributedChatDemo.git
作者:梁青松
编辑:jq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    7348

    浏览量

    95015
  • 数据库
    +关注

    关注

    7

    文章

    4083

    浏览量

    68538
  • ui
    ui
    +关注

    关注

    0

    文章

    211

    浏览量

    22463
  • 代码
    +关注

    关注

    30

    文章

    4976

    浏览量

    74376

原文标题:一款鸿蒙分布式聊天室应用!

文章出处:【微信号:gh_834c4b3d87fe,微信公众号:OpenHarmony技术社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    2022全新版!Java分布式架构设计与开发实战(完结)

    2022全新版!Java分布式架构设计与开发实战(完结) 分库分表实战:Java海量数据存储架构设计 在现代互联网应用中,随着业务规模的指数级增长,数据库性能瓶颈已成为制约系统发展的
    发表于 03-30 15:20

    TiDB分布式数据库运维实践

    TiDB 是 PingCAP 开发的开源分布式关系型数据库,兼容 MySQL 5.7 协议,底层存储基于 TiKV(分布式 KV 存储)和 RocksDB。它解决的核心问题是:当单机
    的头像 发表于 03-04 15:44 283次阅读

    SC-3568HA:解锁鸿蒙全权限API与分布式能力的工业控制平台

    传统嵌入式开发面临硬件碎片化、高权限功能缺失、分布式协同复杂及自动化测试不足等痛点。SC-3568HA开发板基于鸿蒙系统,通过统一内核抽象层和硬件驱动框架解决兼容问题,开放全量系统AP
    的头像 发表于 12-18 11:27 7554次阅读
    SC-3568HA:解锁<b class='flag-5'>鸿蒙</b>全权限API与<b class='flag-5'>分布式</b>能力的工业控制平台

    深入理解分布式共识算法 Raft

    “不可靠的网络”、“不稳定的时钟”和“节点的故障”都是在分布式系统中常见的问题,在文章开始前,我们先来看一下:如果在分布式系统中网络不可靠会发生什么样的问题。 有以下 3 个服务构成的分布式
    的头像 发表于 11-27 14:51 433次阅读
    深入理解<b class='flag-5'>分布式</b>共识算法 Raft

    如何解决分布式光伏计量难题?

    %。同时,可提升发电效率、降低发电成本的新型技术逐步落地,推动光伏系统向更高效、更紧凑的方向发展,进而对电表在精度、数据更新速度及适配性方面也提出了更高要求。 分布式光伏遇计量难题 分布式光伏常用 “自己发的电自己用,用不完的卖
    的头像 发表于 11-07 14:55 412次阅读
    如何解决<b class='flag-5'>分布式</b>光伏计量难题?

    【节能学院】Acrel-1000DP分布式光伏监控系统在奉贤平高食品 4.4MW 分布式光伏中应用

    分布式光伏本地和远程通信方案,并研究分布式光伏采集模型的构建、多源数据融合估计、面向分布式光伏的有功、无功功率优化控制等关键技术,实现了对小容量工商业
    的头像 发表于 08-23 08:04 3660次阅读
    【节能学院】Acrel-1000DP<b class='flag-5'>分布式</b>光伏监控系统在奉贤平高食品 4.4MW <b class='flag-5'>分布式</b>光伏中应用

    分布式光伏发电监测系统技术方案

    分布式光伏发电监测系统技术方案 柏峰【BF-GFQX】一、系统目标 :分布式光伏发电监测系统旨在通过智能化的监测手段,实现对分布式光伏电站的全方位、高精度、实时化管理。该系统能
    的头像 发表于 08-22 10:51 3466次阅读
    <b class='flag-5'>分布式</b>光伏发电监测系统技术方案

    开鸿开发板深度体验:从开源鸿蒙开发到AI场景实践

    的KaihongBoard-3588S-SBC和KaihongBoard-3576-SBC被评为“2025OpenHarmony明星开发板”,可实现设备快速开源鸿蒙化升级、分布式互联协同、弹性部署等能力。
    的头像 发表于 07-03 17:03 1976次阅读
    开鸿<b class='flag-5'>开发</b>板深度体验:从开源<b class='flag-5'>鸿蒙</b><b class='flag-5'>开发</b>到AI场景实践

    鸿蒙5开发宝藏案例分享---一多开发实例(音乐)

    各位开发者小伙伴们好呀!今天咱们来点硬核干货!最近在鸿蒙文档中心挖到一座“金矿”——官方竟然暗藏了100+实战案例,从分布式架构到交互动效优化应有尽有!这些案例不仅藏着华为工程师的私房技巧,还直接
    的头像 发表于 06-30 11:54 853次阅读

    vsan数据恢复—vsan分布式服务器节点上raid数据恢复案例

    4台服务器基于vsan分布式架构的组建一个集群。每台节点服务器上有2组由6块硬盘组建的raid磁盘阵列,上层存放虚拟机文件。 某一个服务器节点上有一块硬盘离线,vsan的
    的头像 发表于 06-18 12:29 666次阅读

    鸿蒙5开发宝藏案例分享---应用接续提升内容发布体验

    : [distributedAsset] // 关键!这里放的是分布式文件引用 }); // 激活数据同步(相当于启动数据快递服务) this.distributedObject.s
    发表于 06-03 18:25

    鸿蒙5开发宝藏案例分享---一多开发实例(游戏)

    十年前藏的现金一样惊喜!)这些藏在文档深处的\"武功秘籍\",能帮我们轻松实现分布式游戏、跨端协同这些听起来很酷的功能。快上车,带你解锁鸿蒙开发的正确姿势! 一、分布式游戏手柄
    发表于 06-03 18:22

    曙光存储领跑中国分布式存储市场

    近日,赛迪顾问发布《中国分布式存储市场研究报告(2025)》,指出2024 年中国分布式存储市场首次超过集中式存储,规模达 198.2 亿元,增速 43.7%。
    的头像 发表于 05-19 16:50 1454次阅读

    开源鸿蒙开发新体验,开鸿Bot系列今日开启预售!

    支持。   ●新安全:KaihongOS作为唯一通过公安部安全检测认证的开源鸿蒙操作系统,通过“数据不出域+分布式安全防御+应用安全”机制,为用户数据和系统运行提供全方位、深层次的安全
    发表于 05-16 14:13

    分布式光伏电力问题层出不穷?安科瑞分布式光伏运维系统来“救场”

    一、分布式光伏电力运维,痛点大揭秘​ ​ 分布式光伏作为实现绿色能源转型的关键一环,近年来在我国得到了迅猛发展。国家能源局数据显示,截至 2023 年底,中国分布式光伏电站累计并网容量
    的头像 发表于 05-07 17:14 1092次阅读
    <b class='flag-5'>分布式</b>光伏电力问题层出不穷?安科瑞<b class='flag-5'>分布式</b>光伏运维系统来“救场”