0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于鴻蒙分布式數(shù)據(jù)服務(wù)開發(fā)的聊天室應(yīng)用

OpenHarmony技術(shù)社區(qū) ? 來源:HarmonyOS技術(shù)社區(qū) ? 作者:梁青松 ? 2021-12-03 10:35 ? 次閱讀

之前給大家介紹過《HarmonyOS 分布式之仿抖音應(yīng)用》,此次給大家介紹一下基于鴻蒙分布式數(shù)據(jù)服務(wù)開發(fā)的聊天室應(yīng)用,模擬現(xiàn)實(shí)中的聊天室對(duì)話,可以與小伙伴們互動(dòng)、分享自己的故事給小伙伴。

主要知識(shí)點(diǎn)

分布式數(shù)據(jù)服務(wù)

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

官方介紹:分布式數(shù)據(jù)服務(wù)主要實(shí)現(xiàn)用戶設(shè)備中應(yīng)用程序的數(shù)據(jù)內(nèi)容的分布式同步。

當(dāng)設(shè)備 1 上的應(yīng)用 A 在分布式數(shù)據(jù)庫中增、刪、改數(shù)據(jù)后,設(shè)備 2 上的應(yīng)用 A 也可以獲取到該數(shù)據(jù)庫變化,總結(jié)一句話:多個(gè)設(shè)備共用一個(gè)數(shù)據(jù)庫。

主頁代碼

沒有特別復(fù)雜的邏輯,主要是分布式數(shù)據(jù)服務(wù)的使用,關(guān)鍵地方都有注釋。
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;
//聊天數(shù)據(jù)
privatefinalListlistData=newArrayList<>();
//聊天數(shù)據(jù)適配器
privateChatProviderchatProvider;
//輸入框
privateTextFieldtfContent;
//發(fā)送按鈕
privateButtonbtnSend;

//分布式數(shù)據(jù)庫管理器
privateKvManagerkvManager;
//分布式數(shù)據(jù)庫
privateSingleKvStoresingleKvStore;
//數(shù)據(jù)庫名稱
privatestaticfinalStringSTORE_NAME="ChatStore";
//存入的列表數(shù)據(jù)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();
}

/**
*請(qǐng)求分布式權(quán)限
*/
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);

//輸入框內(nèi)容變化監(jiān)聽
tfContent.addTextObserver((text,start,before,count)->{
btnSend.setEnabled(text.length()!=0);
});
//點(diǎn)擊發(fā)送按鈕
btnSend.setClickedListener(component->{
Stringcontent=tfContent.getText().trim();
listData.add(newChatDataBean(Tools.getDeviceId(mContext),picIndex,content));
//存入數(shù)據(jù)庫中
singleKvStore.putString(KEY_DATA,ZSONObject.toZSONString(listData));

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

/**
*初始化分布式數(shù)據(jù)庫
*/
privatevoidinitDatabase(){
//創(chuàng)建分布式數(shù)據(jù)庫管理器
kvManager=KvManagerFactory.getInstance().createKvManager(newKvManagerConfig(this));

//數(shù)據(jù)庫配置
Optionsoptions=newOptions();
options.setCreateIfMissing(true)//設(shè)置數(shù)據(jù)庫不存在時(shí)是否創(chuàng)建
.setEncrypt(false)//設(shè)置數(shù)據(jù)庫是否加密
.setKvStoreType(KvStoreType.SINGLE_VERSION);//數(shù)據(jù)庫類型
//創(chuàng)建分布式數(shù)據(jù)庫
singleKvStore=kvManager.getKvStore(options,STORE_NAME);
//監(jiān)聽數(shù)據(jù)庫數(shù)據(jù)改變
singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,newKvStoreObserver(){
@Override
publicvoidonChange(ChangeNotificationchangeNotification){
ListinsertEntries=changeNotification.getInsertEntries();
ListupdateEntries=changeNotification.getUpdateEntries();

//第一次存入數(shù)據(jù),獲取insertEntries
if(insertEntries.size()>0){
for(Entryentry:insertEntries){
if(KEY_DATA.equals(entry.getKey())){
//回調(diào)為非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())){
//回調(diào)為非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();
//沒有找到,首次進(jìn)入
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":"多設(shè)備協(xié)同",
"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="數(shù)據(jù):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="點(diǎn)擊+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{
//顯示數(shù)據(jù)
privateTexttext;
//分布式數(shù)據(jù)庫管理器
privateKvManagerkvManager;
//分布式數(shù)據(jù)庫
privateSingleKvStoresingleKvStore;
//數(shù)據(jù)庫名稱
privatestaticfinalStringSTORE_NAME="MyStore";
//存入的數(shù)據(jù)key
privatestaticfinalStringKEY_COUNT="key_count";

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

/**
*請(qǐng)求分布式權(quán)限
*/
privatevoidrequestPermission(){
if(verifySelfPermission(DISTRIBUTED_DATASYNC)!=IBundleManager.PERMISSION_GRANTED){
if(canRequestPermission(DISTRIBUTED_DATASYNC)){
requestPermissionsFromUser(newString[]{DISTRIBUTED_DATASYNC},0);
}
}
}

/**
*初始化分布式數(shù)據(jù)庫
*/
privatevoidinitDatabase(){
//創(chuàng)建分布式數(shù)據(jù)庫管理器
kvManager=KvManagerFactory.getInstance().createKvManager(newKvManagerConfig(this));

//數(shù)據(jù)庫配置
Optionsoptions=newOptions();
options.setCreateIfMissing(true)//設(shè)置數(shù)據(jù)庫不存在時(shí)是否創(chuàng)建
.setEncrypt(false)//設(shè)置數(shù)據(jù)庫是否加密
.setKvStoreType(KvStoreType.SINGLE_VERSION);//數(shù)據(jù)庫類型
//創(chuàng)建分布式數(shù)據(jù)庫
singleKvStore=kvManager.getKvStore(options,STORE_NAME);
//監(jiān)聽數(shù)據(jù)庫數(shù)據(jù)改變
singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,newKvStoreObserver(){
@Override
publicvoidonChange(ChangeNotificationchangeNotification){
ListinsertEntries=changeNotification.getInsertEntries();
ListupdateEntries=changeNotification.getUpdateEntries();

//第一次存入數(shù)據(jù),獲取insertEntries
if(insertEntries.size()>0){
for(Entryentry:insertEntries){
if(KEY_COUNT.equals(entry.getKey())){
//回調(diào)為非UI線程,需要在UI線程更新UI
getUITaskDispatcher().syncDispatch(()->{
intcount=entry.getValue().getInt();
text.setText("數(shù)據(jù):"+count);
});
}
}
}elseif(updateEntries.size()>0){
for(Entryentry:updateEntries){
if(KEY_COUNT.equals(entry.getKey())){
//回調(diào)為非UI線程,需要在UI線程更新UI
getUITaskDispatcher().syncDispatch(()->{
intcount=entry.getValue().getInt();
text.setText("數(shù)據(jù):"+count);
});
}
}
}
}
});

}

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

//點(diǎn)擊事件
button.setClickedListener(component->{
try{
intcount=singleKvStore.getInt(KEY_COUNT);
singleKvStore.putInt(KEY_COUNT,count+1);
}catch(KvStoreExceptione){
e.printStackTrace();
//沒有找到,首次進(jìn)入
if(e.getKvStoreErrorCode()==KvStoreErrorCode.KEY_NOT_FOUND){
intcount=0;
singleKvStore.putInt(KEY_COUNT,count+1);
}
}
});
}
}
注釋比較詳細(xì),主要注意 2 個(gè)點(diǎn):
  • 獲取數(shù)據(jù)時(shí)加入 try catch 塊,處理 key 未找到的情況。

  • 數(shù)據(jù)庫數(shù)據(jù)改變監(jiān)聽回調(diào)是非 UI 線程,如果更新 UI 必須切換到 UI 線程。

以上簡單案例就是讓你快速掌握分布式數(shù)據(jù)服務(wù):多個(gè)設(shè)備相同的應(yīng)用之間使用同一個(gè)數(shù)據(jù)庫。 項(xiàng)目地址(需要登錄才能看到演示圖):
https://gitee.com/liangdidi/DistributedChatDemo.git
作者:梁青松
編輯:jq
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    6754

    瀏覽量

    88611
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    3734

    瀏覽量

    64170
  • ui
    ui
    +關(guān)注

    關(guān)注

    0

    文章

    202

    瀏覽量

    21315
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4694

    瀏覽量

    68075

原文標(biāo)題:一款鴻蒙分布式聊天室應(yīng)用!

文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙開發(fā)接口數(shù)據(jù)管理:【@ohos.data.distributedData (分布式數(shù)據(jù)管理)】

    分布式數(shù)據(jù)管理為應(yīng)用程序提供不同設(shè)備間數(shù)據(jù)庫的分布式協(xié)同能力。通過調(diào)用分布式數(shù)據(jù)各個(gè)接口,應(yīng)用程
    的頭像 發(fā)表于 06-07 09:30 ?802次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>開發(fā)</b>接口<b class='flag-5'>數(shù)據(jù)</b>管理:【@ohos.data.distributedData (<b class='flag-5'>分布式</b><b class='flag-5'>數(shù)據(jù)</b>管理)】

    HarmonyOS開發(fā)實(shí)例:【分布式數(shù)據(jù)服務(wù)

    分布式數(shù)據(jù)服務(wù)(Distributed Data Service,DDS)為應(yīng)用程序提供不同設(shè)備間數(shù)據(jù)分布式的能力。
    的頭像 發(fā)表于 04-18 10:18 ?608次閱讀
    HarmonyOS<b class='flag-5'>開發(fā)</b>實(shí)例:【<b class='flag-5'>分布式</b><b class='flag-5'>數(shù)據(jù)服務(wù)</b>】

    鴻蒙HarmonyOS開發(fā)實(shí)例:【分布式關(guān)系型數(shù)據(jù)庫】

    使用[@ohos.data.relationalStore]接口和[@ohos.distributedDeviceManager]?接口展示了在eTS中分布式關(guān)系型數(shù)據(jù)庫的使用,在增、刪、改、查的基本操作外,還包括分布式數(shù)據(jù)庫的
    的頭像 發(fā)表于 04-11 09:52 ?711次閱讀
    <b class='flag-5'>鴻蒙</b>HarmonyOS<b class='flag-5'>開發(fā)</b>實(shí)例:【<b class='flag-5'>分布式</b>關(guān)系型<b class='flag-5'>數(shù)據(jù)</b>庫】

    鴻蒙HarmonyOS開發(fā)實(shí)戰(zhàn):【分布式音樂播放】

    本示例使用fileIo獲取指定音頻文件,并通過AudioPlayer完成了音樂的播放完成了基本的音樂播放、暫停、上一曲、下一曲功能;并使用DeviceManager完成了分布式設(shè)備列表的顯示和分布式能力完成了音樂播放狀態(tài)的跨設(shè)備分享。
    的頭像 發(fā)表于 04-10 17:51 ?760次閱讀
    <b class='flag-5'>鴻蒙</b>HarmonyOS<b class='flag-5'>開發(fā)</b>實(shí)戰(zhàn):【<b class='flag-5'>分布式</b>音樂播放】

    UEFIRC:運(yùn)行于UEFI環(huán)境下的IRC聊天室

    據(jù)悉,開源開發(fā)者Phillip Tennen展示了基于UEFI的沉浸IRC網(wǎng)絡(luò)聊天室:UREFIRC原型設(shè)計(jì)。該設(shè)計(jì)無需進(jìn)入操作系統(tǒng),僅在UEFI環(huán)境內(nèi)運(yùn)行。
    的頭像 發(fā)表于 04-08 16:16 ?531次閱讀

    鴻蒙OS 分布式任務(wù)調(diào)度

    形式、數(shù)據(jù)結(jié)構(gòu)、服務(wù)描述語言,屏蔽硬件差異;支持遠(yuǎn)程啟動(dòng)、遠(yuǎn)程調(diào)用、業(yè)務(wù)無縫遷移等分布式任務(wù)。 分布式任務(wù)調(diào)度平臺(tái)在底層實(shí)現(xiàn) Ability(分布式
    的頭像 發(fā)表于 01-29 16:50 ?420次閱讀

    分布式節(jié)點(diǎn)服務(wù)器是什么?

    部署在不同的服務(wù)器上進(jìn)行處理和存儲(chǔ),以實(shí)現(xiàn)負(fù)載均衡和容錯(cuò)處理。這種架構(gòu)模式旨在提高系統(tǒng)的可擴(kuò)展性、可靠性和性能表現(xiàn),以滿足大規(guī)模數(shù)據(jù)處理、復(fù)雜任務(wù)處理等需求。 分布式節(jié)點(diǎn)服務(wù)器的實(shí)現(xiàn)方
    的頭像 發(fā)表于 01-12 15:04 ?643次閱讀
    <b class='flag-5'>分布式</b>節(jié)點(diǎn)<b class='flag-5'>服務(wù)</b>器是什么?

    鴻蒙千帆起】《開心消消樂》完成鴻蒙原生應(yīng)用開發(fā),創(chuàng)新多端聯(lián)動(dòng)用戶體驗(yàn)

    更優(yōu)質(zhì)的用戶體驗(yàn),基于強(qiáng)大的 AI 能力還可以實(shí)現(xiàn)精準(zhǔn)識(shí)別、精確投放,為伙伴提供新流量,并共享全場(chǎng)景服務(wù)分發(fā),助力生態(tài)共贏。數(shù)據(jù)顯示,截至今年 8 月份,鴻蒙生態(tài)的設(shè)備數(shù)已超過 7 億,鴻蒙
    發(fā)表于 01-03 10:22

    鴻蒙原生應(yīng)用開發(fā)——分布式數(shù)據(jù)對(duì)象

    、分布式數(shù)據(jù)對(duì)象保存 6、分布式數(shù)據(jù)對(duì)象訂閱(數(shù)據(jù)變更,上下線) 7、分布式
    發(fā)表于 12-08 10:01

    分布式系統(tǒng)硬件資源池原理和接入實(shí)踐

    提供更好的服務(wù)體驗(yàn)。 圖 3 鴻蒙硬件資源池支持各類消費(fèi)者場(chǎng)景 2.2 開發(fā)者場(chǎng)景 對(duì)于開發(fā)者來說,由于分布式硬件資源池將跨設(shè)備硬件調(diào)用的
    發(fā)表于 12-06 10:02

    zookeeper分布式原理

    Zookeeper是一個(gè)開源的分布式協(xié)調(diào)服務(wù),可以用于構(gòu)建高可用、高性能的分布式系統(tǒng)。它提供了一個(gè)簡單且高效的層次命名空間,可以用來存儲(chǔ)配置信息、狀態(tài)信息、命名服務(wù)等。Zookeepe
    的頭像 發(fā)表于 12-03 16:33 ?561次閱讀

    springcloud 分布式事務(wù)解決方案實(shí)例

    Spring Cloud是一套用于構(gòu)建分布式系統(tǒng)的開發(fā)工具集,可以用于解決分布式系統(tǒng)中的各種問題,包括分布式事務(wù)。在分布式系統(tǒng)中,由于業(yè)務(wù)邏
    的頭像 發(fā)表于 12-03 16:32 ?1018次閱讀

    怎么區(qū)分分布式服務(wù)器和集群服務(wù)器?

      如何區(qū)分分布式服務(wù)器和集群服務(wù)器?許多朋友在選擇服務(wù)器時(shí)不知道分布式服務(wù)器和集群
    的頭像 發(fā)表于 11-29 15:20 ?582次閱讀

    springcloud如何實(shí)現(xiàn)分布式

    Spring Cloud是基于Spring Boot開發(fā)的一套分布式系統(tǒng)解決方案,它主要包括了多個(gè)子項(xiàng)目,如服務(wù)注冊(cè)與發(fā)現(xiàn)、配置中心、負(fù)載均衡、斷路器、路由等等。通過使用Spring Cloud
    的頭像 發(fā)表于 11-16 11:01 ?602次閱讀

    springclould分布式教程

    Spring Cloud是一個(gè)基于Spring Boot的分布式系統(tǒng)開發(fā)工具,它提供了一系列的分布式系統(tǒng)解決方案,可以幫助開發(fā)者快速構(gòu)建和部署分布式
    的頭像 發(fā)表于 11-16 10:59 ?422次閱讀