之前給大家介紹過《HarmonyOS 分布式之仿抖音應(yīng)用》,此次給大家介紹一下基于鴻蒙分布式數(shù)據(jù)服務(wù)開發(fā)的聊天室應(yīng)用,模擬現(xiàn)實中的聊天室對話,可以與小伙伴們互動、分享自己的故事給小伙伴。
主要知識點
分布式數(shù)據(jù)服務(wù):
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/database-mdds-guidelines-0000000000030122
官方介紹:分布式數(shù)據(jù)服務(wù)主要實現(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é)一句話:多個設(shè)備共用一個數(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();
}
/**
*請求分布式權(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);
});
//點擊發(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ù)庫不存在時是否創(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();
//沒有找到,首次進入
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="點擊+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();
}
/**
*請求分布式權(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ù)庫不存在時是否創(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);
//點擊事件
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 個點:-
獲取數(shù)據(jù)時加入 try catch 塊,處理 key 未找到的情況。
-
數(shù)據(jù)庫數(shù)據(jù)改變監(jiān)聽回調(diào)是非 UI 線程,如果更新 UI 必須切換到 UI 線程。
以上簡單案例就是讓你快速掌握分布式數(shù)據(jù)服務(wù):多個設(shè)備相同的應(yīng)用之間使用同一個數(shù)據(jù)庫。 項目地址(需要登錄才能看到演示圖):
https://gitee.com/liangdidi/DistributedChatDemo.git
責(zé)任編輯:haq
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
6909瀏覽量
88849 -
鴻蒙系統(tǒng)
+關(guān)注
關(guān)注
183文章
2634瀏覽量
66224 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1967瀏覽量
30033
原文標題:一款鴻蒙分布式聊天室應(yīng)用!
文章出處:【微信號:gh_834c4b3d87fe,微信公眾號:OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論