HarmonyOS 分布式之聊天室應(yīng)用
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
介紹
之前給大家介紹過【#星光計(jì)劃1.0# HarmonyOS 分布式之仿抖音應(yīng)用】,此次給大家介紹一下基于鴻蒙分布式數(shù)據(jù)服務(wù)開發(fā)的聊天室應(yīng)用,模擬現(xiàn)實(shí)中的聊天室對話,可以與小伙伴們互動、分享自己的故事給小伙伴。
效果演示

項(xiàng)目類說明

主要知識點(diǎn)
分布式數(shù)據(jù)服務(wù)
官方介紹:分布式數(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)鍵地方都有注釋。
- import com.ldd.myapp.bean.ChatDataBean;
- import com.ldd.myapp.provider.ChatProvider;
- import com.ldd.myapp.util.Tools;
- import ohos.aafwk.ability.AbilitySlice;
- import ohos.aafwk.content.Intent;
- import ohos.agp.components.Button;
- import ohos.agp.components.ListContainer;
- import ohos.agp.components.TextField;
- import ohos.app.Context;
- import ohos.bundle.IBundleManager;
- import ohos.data.distributed.common.*;
- import ohos.data.distributed.user.SingleKvStore;
- import ohos.utils.zson.ZSONArray;
- import ohos.utils.zson.ZSONObject;
- import java.util.ArrayList;
- import java.util.List;
- import static ohos.security.SystemPermission.DISTRIBUTED_DATASYNC;
- /**
- * 主頁
- */
- public class MainAbilitySlice extends AbilitySlice {
- private Context mContext;
- // 聊天列表
- private ListContainer lcList;
- // 聊天數(shù)據(jù)
- private final List<ChatDataBean> listData = new ArrayList<>();
- // 聊天數(shù)據(jù)適配器
- private ChatProvider chatProvider;
- // 輸入框
- private TextField tfContent;
- // 發(fā)送按鈕
- private Button btnSend;
- // 分布式數(shù)據(jù)庫管理器
- private KvManager kvManager;
- // 分布式數(shù)據(jù)庫
- private SingleKvStore singleKvStore;
- // 數(shù)據(jù)庫名稱
- private static final String STORE_NAME = "ChatStore";
- // 存入的列表數(shù)據(jù)key
- private static final String KEY_DATA = "key_data";
- // 存入的頭像索引
- private static final String KEY_PIC_INDEX = "key_pic_index";
- private int picIndex = 0;
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_main);
- mContext = this;
- requestPermission();
- initComponent();
- initDatabase();
- }
- /**
- * 請求分布式權(quán)限
- */
- private void requestPermission() {
- if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) {
- if (canRequestPermission(DISTRIBUTED_DATASYNC)) {
- requestPermissionsFromUser(new String[]{DISTRIBUTED_DATASYNC}, 0);
- }
- }
- }
- /**
- * 初始化組件
- */
- private void initComponent() {
- 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 = new ChatProvider(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 -> {
- String content = tfContent.getText().trim();
- listData.add(new ChatDataBean(Tools.getDeviceId(mContext),picIndex,content));
- // 存入數(shù)據(jù)庫中
- singleKvStore.putString(KEY_DATA, ZSONObject.toZSONString(listData));
- // 清空輸入框
- tfContent.setText("");
- });
- }
- /**
- * 初始化分布式數(shù)據(jù)庫
- */
- private void initDatabase() {
- // 創(chuàng)建分布式數(shù)據(jù)庫管理器
- kvManager = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(this));
- // 數(shù)據(jù)庫配置
- Options options = new Options();
- 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, new KvStoreObserver() {
- @Override
- public void onChange(ChangeNotification changeNotification) {
- List<Entry> insertEntries = changeNotification.getInsertEntries();
- List<Entry> updateEntries = changeNotification.getUpdateEntries();
- // 第一次存入數(shù)據(jù),獲取insertEntries
- if(insertEntries.size()>0){
- for (Entry entry : 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);
- });
- }
- }
- }else if(updateEntries.size()>0){
- for (Entry entry : 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 (KvStoreException e) {
- e.printStackTrace();
- // 沒有找到,首次進(jìn)入
- if (e.getKvStoreErrorCode() == KvStoreErrorCode.KEY_NOT_FOUND) {
- picIndex = 0;
- singleKvStore.putInt(KEY_PIC_INDEX, picIndex + 1);
- }
- }
- }
- @Override
- protected void onStop() {
- super.onStop();
- kvManager.closeKvStore(singleKvStore);
- }
- }
簡單案例
1、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"
- }
- ]
2、布局頁面
- <?xml version="1.0" encoding="utf-8"?>
- <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>
3、MainAbilitySlice代碼
- import ohos.aafwk.ability.AbilitySlice;
- import ohos.aafwk.content.Intent;
- import ohos.agp.components.Button;
- import ohos.agp.components.ListContainer;
- import ohos.agp.components.Text;
- import ohos.agp.components.TextField;
- import ohos.bundle.IBundleManager;
- import ohos.data.distributed.common.*;
- import ohos.data.distributed.user.SingleKvStore;
- import ohos.utils.zson.ZSONArray;
- import java.util.List;
- import static ohos.security.SystemPermission.DISTRIBUTED_DATASYNC;
- public class MainAbilitySlice extends AbilitySlice {
- // 顯示數(shù)據(jù)
- private Text text;
- // 分布式數(shù)據(jù)庫管理器
- private KvManager kvManager;
- // 分布式數(shù)據(jù)庫
- private SingleKvStore singleKvStore;
- // 數(shù)據(jù)庫名稱
- private static final String STORE_NAME = "MyStore";
- // 存入的數(shù)據(jù)key
- private static final String KEY_COUNT = "key_count";
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_main);
- requestPermission();
- initDatabase();
- initComponent();
- }
- /**
- * 請求分布式權(quán)限
- */
- private void requestPermission() {
- if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) {
- if (canRequestPermission(DISTRIBUTED_DATASYNC)) {
- requestPermissionsFromUser(new String[]{DISTRIBUTED_DATASYNC}, 0);
- }
- }
- }
- /**
- * 初始化分布式數(shù)據(jù)庫
- */
- private void initDatabase() {
- // 創(chuàng)建分布式數(shù)據(jù)庫管理器
- kvManager = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(this));
- // 數(shù)據(jù)庫配置
- Options options = new Options();
- 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, new KvStoreObserver() {
- @Override
- public void onChange(ChangeNotification changeNotification) {
- List<Entry> insertEntries = changeNotification.getInsertEntries();
- List<Entry> updateEntries = changeNotification.getUpdateEntries();
- // 第一次存入數(shù)據(jù),獲取insertEntries
- if (insertEntries.size() > 0) {
- for (Entry entry : insertEntries) {
- if (KEY_COUNT.equals(entry.getKey())) {
- // 回調(diào)為非UI線程,需要在UI線程更新UI
- getUITaskDispatcher().syncDispatch(() -> {
- int count = entry.getValue().getInt();
- text.setText("數(shù)據(jù):"+count);
- });
- }
- }
- } else if (updateEntries.size() > 0) {
- for (Entry entry : updateEntries) {
- if (KEY_COUNT.equals(entry.getKey())) {
- // 回調(diào)為非UI線程,需要在UI線程更新UI
- getUITaskDispatcher().syncDispatch(() -> {
- int count = entry.getValue().getInt();
- text.setText("數(shù)據(jù):"+count);
- });
- }
- }
- }
- }
- });
- }
- /**
- * 初始化組件
- */
- private void initComponent() {
- text = (Text) findComponentById(ResourceTable.Id_text);
- Button button = (Button) findComponentById(ResourceTable.Id_button);
- // 點(diǎn)擊事件
- button.setClickedListener(component -> {
- try {
- int count = singleKvStore.getInt(KEY_COUNT);
- singleKvStore.putInt(KEY_COUNT, count + 1);
- } catch (KvStoreException e) {
- e.printStackTrace();
- // 沒有找到,首次進(jìn)入
- if (e.getKvStoreErrorCode() == KvStoreErrorCode.KEY_NOT_FOUND) {
- int count = 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ù)庫。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)