好好学习

扫一扫关注

HarmonyOS 分布式之聊天室应用

下载文本     阴势2022-09-28 12:43:45 27510

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

介绍

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

效果演示

#星光计划1.0# Harmo<i></i>nyOS 分布式之聊天室应用-鸿蒙HarmonyOS技术社区
项目类说明
#星光计划1.0# Harmo<i></i>nyOS 分布式之聊天室应用-鸿蒙HarmonyOS技术社区
主要知识点

分布式数据服务

官方介绍:分布式数据服务主要实现用户设备中应用程序的数据内容的分布式同步。当设备1上的应用A在分布式数据库中增、删、改数据后,设备2上的应用A也可以获取到该数据库变化,总结一句话:多个设备共用一个数据库。

主页代码

没有特别复杂的逻辑,主要是分布式数据服务的使用,关键地方都有注释。

  1. import com.ldd.myapp.bean.ChatDataBean; import com.ldd.myapp.provider.ChatProvider; 
  2. import com.ldd.myapp.util.Tools; import ohos.aafwk.ability.AbilitySlice; 
  3. import ohos.aafwk.content.Intent; import ohos.agp.components.Button; 
  4. import ohos.agp.components.ListContainer; import ohos.agp.components.TextField; 
  5. import ohos.app.Context; import ohos.bundle.IBundleManager; 
  6. import ohos.data.distributed.common.*; import ohos.data.distributed.user.SingleKvStore; 
  7. import ohos.utils.zson.ZSONArray; import ohos.utils.zson.ZSONObject; 
  8.  import java.util.ArrayList; 
  9. import java.util.List;  
  10. import static ohos.security.SystemPermission.DISTRIBUTED_DATASYNC;  
  11.  public class MainAbilitySlice extends AbilitySlice { 
  12.     private Context mContext;     // 聊天列表 
  13.     private ListContainer lcList;     // 聊天数据 
  14.     private final List listData = new ArrayList<>();     // 聊天数据适配器 
  15.     private ChatProvider chatProvider;     // 输入框 
  16.     private TextField tfContent;     // 发送按钮 
  17.     private Button btnSend;  
  18.     // 分布式数据库管理器     private KvManager kvManager; 
  19.     // 分布式数据库     private SingleKvStore singleKvStore; 
  20.     // 数据库名称     private static final String STORE_NAME = "ChatStore"; 
  21.     // 存入的列表数据key     private static final String KEY_DATA = "key_data"; 
  22.     // 存入的头像索引     private static final String KEY_PIC_INDEX = "key_pic_index"; 
  23.     private int picIndex = 0;  
  24.     @Override     public void onStart(Intent intent) { 
  25.         super.onStart(intent);         super.setUIContent(ResourceTable.Layout_ability_main); 
  26.         mContext = this;         requestPermission(); 
  27.         initComponent();         initDatabase(); 
  28.     }  
  29.          private void requestPermission() { 
  30.         if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) {             if (canRequestPermission(DISTRIBUTED_DATASYNC)) { 
  31.                 requestPermissionsFromUser(new String[]{DISTRIBUTED_DATASYNC}, 0);             } 
  32.         }     } 
  33.       
  34.     private void initComponent() {         lcList = (ListContainer) findComponentById(ResourceTable.Id_lc_list); 
  35.         tfContent = (TextField) findComponentById(ResourceTable.Id_tf_content);         tfContent.setAdjustInputPanel(true); 
  36.         btnSend = (Button) findComponentById(ResourceTable.Id_btn_send);         btnSend.setEnabled(false); 
  37.          // 初始化适配器 
  38.         chatProvider = new ChatProvider(mContext, listData);         lcList.setItemProvider(chatProvider); 
  39.          // 输入框内容变化监听 
  40.         tfContent.addTextObserver((text, start, before, count) -> {             btnSend.setEnabled(text.length() != 0); 
  41.         });         // 点击发送按钮 
  42.         btnSend.setClickedListener(component -> {             String content = tfContent.getText().trim(); 
  43.             listData.add(new ChatDataBean(Tools.getDeviceId(mContext),picIndex,content));             // 存入数据库中 
  44.             singleKvStore.putString(KEY_DATA, ZSONObject.toZSonString(listData));  
  45.             // 清空输入框             tfContent.setText(""); 
  46.         });     } 
  47.       
  48.     private void initDatabase() {         // 创建分布式数据库管理器 
  49.         kvManager = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(this));  
  50.         // 数据库配置         Options options = new Options(); 
  51.         options.setCreateIfMissing(true) // 设置数据库不存在时是否创建                 .setEncrypt(false) // 设置数据库是否加密 
  52.                 .setKvStoreType(KvStoreType.SINGLE_VERSION); //数据库类型         // 创建分布式数据库 
  53.         singleKvStore = kvManager.getKvStore(options, STORE_NAME);         // 监听数据库数据改变 
  54.         singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, new KvStoreObserver() {             @Override 
  55.             public void onChange(ChangeNotification changeNotification) {                 List insertEntries = changeNotification.getInsertEntries(); 
  56.                 List updateEntries = changeNotification.getUpdateEntries();  
  57.                 // 第一次存入数据,获取insertEntries                 if(insertEntries.size()>0){ 
  58.                     for (Entry entry : insertEntries) {                         if (KEY_DATA.equals(entry.getKey())) { 
  59.                             // 回调为非UI线程,需要在UI线程更新UI                             getUITaskDispatcher().syncDispatch(() -> { 
  60.                                 listData.clear();                                 listData.addAll(ZSONArray.stringToClassList(entry.getValue().getString(),ChatDataBean.class)); 
  61.                                 chatProvider.notifyDataChanged();                                 lcList.scrollTo(listData.size() - 1); 
  62.                             });                         } 
  63.                     }                 }else if(updateEntries.size()>0){ 
  64.                     for (Entry entry : updateEntries) {                         if (KEY_DATA.equals(entry.getKey())) { 
  65.                             // 回调为非UI线程,需要在UI线程更新UI                             getUITaskDispatcher().syncDispatch(() -> { 
  66.                                 listData.clear();                                 listData.addAll(ZSONArray.stringToClassList(entry.getValue().getString(),ChatDataBean.class)); 
  67.                                 chatProvider.notifyDataChanged();                                 lcList.scrollTo(listData.size() - 1); 
  68.                             });                         } 
  69.                     }                 } 
  70.             }         }); 
  71.          try { 
  72.             picIndex = singleKvStore.getInt(KEY_PIC_INDEX);             singleKvStore.putInt(KEY_PIC_INDEX, picIndex + 1); 
  73.         } catch (KvStoreException e) {             e.printStackTrace(); 
  74.             // 没有找到,首次进入             if (e.getKvStoreErrorCode() == KvStoreErrorCode.KEY_NOT_FOUND) { 
  75.                 picIndex = 0;                 singleKvStore.putInt(KEY_PIC_INDEX, picIndex + 1); 
  76.             }         } 
  77.     }  
  78.     @Override     protected void onStop() { 
  79.         super.onStop();         kvManager.closeKvStore(singleKvStore); 
  80.     } } 
简单案例1、config.json配置
  1. "reqPermissions": [       { 
  2.         "reason": "多设备协同",         "name": "ohos.permission.DISTRIBUTED_DATASYNC", 
  3.         "usedScene": {           "ability": [ 
  4.             "MainAbility"           ], 
  5.           "when": "always"         } 
  6.       },       { 
  7.         "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"       }, 
  8.       {         "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO" 
  9.       },       { 
  10.         "name": "ohos.permission.GET_BUNDLE_INFO"       } 
  11.     ] 
2、布局页面
  1.      xmlns:ohos="http://schemas.huawei.com/res/ohos"     ohos:height="match_parent" 
  2.     ohos:width="match_parent"     ohos:alignment="center" 
  3.     ohos:orientation="vertical">  
  4.             ohos:height="match_content"         ohos:width="match_content" 
  5.         ohos:text="数据:0"         ohos:text_size="15fp"/> 
  6.              ohos:margin="20vp"         ohos:id="$+id:button" 
  7.         ohos:height="match_content"         ohos:width="match_parent" 
  8.         ohos:background_element="$graphic:button_bg"         ohos:padding="10vp" 
  9.         ohos:text="点击+1"         ohos:text_color="white" 
  10.         ohos:text_size="15fp"/>  
  11.  
3、MainAbilitySlice代码
  1. import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; 
  2. import ohos.agp.components.Button; import ohos.agp.components.ListContainer; 
  3. import ohos.agp.components.Text; import ohos.agp.components.TextField; 
  4. import ohos.bundle.IBundleManager; import ohos.data.distributed.common.*; 
  5. import ohos.data.distributed.user.SingleKvStore; import ohos.utils.zson.ZSONArray; 
  6.  import java.util.List; 
  7.  import static ohos.security.SystemPermission.DISTRIBUTED_DATASYNC; 
  8.  public class MainAbilitySlice extends AbilitySlice { 
  9.     // 显示数据     private Text text; 
  10.     // 分布式数据库管理器     private KvManager kvManager; 
  11.     // 分布式数据库     private SingleKvStore singleKvStore; 
  12.     // 数据库名称     private static final String STORE_NAME = "MyStore"; 
  13.     // 存入的数据key     private static final String KEY_COUNT = "key_count"; 
  14.      @Override 
  15.     public void onStart(Intent intent) {         super.onStart(intent); 
  16.         super.setUIContent(ResourceTable.Layout_ability_main);         requestPermission(); 
  17.         initDatabase();         initComponent(); 
  18.     }  
  19.          private void requestPermission() { 
  20.         if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) {             if (canRequestPermission(DISTRIBUTED_DATASYNC)) { 
  21.                 requestPermissionsFromUser(new String[]{DISTRIBUTED_DATASYNC}, 0);             } 
  22.         }     } 
  23.       
  24.     private void initDatabase() {         // 创建分布式数据库管理器 
  25.         kvManager = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(this));  
  26.         // 数据库配置         Options options = new Options(); 
  27.         options.setCreateIfMissing(true) // 设置数据库不存在时是否创建                 .setEncrypt(false) // 设置数据库是否加密 
  28.                 .setKvStoreType(KvStoreType.SINGLE_VERSION); //数据库类型         // 创建分布式数据库 
  29.         singleKvStore = kvManager.getKvStore(options, STORE_NAME);         // 监听数据库数据改变 
  30.         singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, new KvStoreObserver() {             @Override 
  31.             public void onChange(ChangeNotification changeNotification) {                 List insertEntries = changeNotification.getInsertEntries(); 
  32.                 List updateEntries = changeNotification.getUpdateEntries();  
  33.                 // 第一次存入数据,获取insertEntries                 if (insertEntries.size() > 0) { 
  34.                     for (Entry entry : insertEntries) {                         if (KEY_COUNT.equals(entry.getKey())) { 
  35.                             // 回调为非UI线程,需要在UI线程更新UI                             getUITaskDispatcher().syncDispatch(() -> { 
  36.                                 int count = entry.getValue().getInt();                                 text.setText("数据:"+count); 
  37.                             });                         } 
  38.                     }                 } else if (updateEntries.size() > 0) { 
  39.                     for (Entry entry : updateEntries) {                         if (KEY_COUNT.equals(entry.getKey())) { 
  40.                             // 回调为非UI线程,需要在UI线程更新UI                             getUITaskDispatcher().syncDispatch(() -> { 
  41.                                 int count = entry.getValue().getInt();                                 text.setText("数据:"+count); 
  42.                             });                         } 
  43.                     }                 } 
  44.             }         }); 
  45.      } 
  46.       
  47.     private void initComponent() {         text = (Text) findComponentById(ResourceTable.Id_text); 
  48.         Button button = (Button) findComponentById(ResourceTable.Id_button);  
  49.         // 点击事件         button.setClickedListener(component -> { 
  50.             try {                 int count = singleKvStore.getInt(KEY_COUNT); 
  51.                 singleKvStore.putInt(KEY_COUNT, count + 1);             } catch (KvStoreException e) { 
  52.                 e.printStackTrace();                 // 没有找到,首次进入 
  53.                 if (e.getKvStoreErrorCode() == KvStoreErrorCode.KEY_NOT_FOUND) {                     int count = 0; 
  54.                     singleKvStore.putInt(KEY_COUNT, count + 1);                 } 
  55.             }         }); 
  56.     } } 

注释比较详细,主要注意2个点:

    获取数据时加入try catch块,处理key未找到的情况 数据库数据改变监听回调是非UI线程,如果更新UI必须切换到UI线程

以上简单案例就是让你快速掌握分布式数据服务:多个设备相同的应用之间使用同一个数据库。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

 
反对 0举报 0 收藏 0 评论 0

(c)2022 haohaoxuexi.cc SYSTEM All Rights Reserved

冀ICP备17031443号-5