当前位置:首页 > IT科技

HarmonyOS 分布式之聊天室应用

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

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

https://harmonyos.51cto.com

介绍

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

效果演示

项目类说明

主要知识点

分布式数据服务

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

主页代码

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

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;     // 聊天数据     private final List<ChatDataBean> listData = new ArrayList<>();     // 聊天数据适配器     private ChatProvider chatProvider;     // 输入框     private TextField tfContent;     // 发送按钮     private Button btnSend;     // 分布式数据库管理器     private KvManager kvManager;     // 分布式数据库     private SingleKvStore singleKvStore;     // 数据库名称     private static final String STORE_NAME = "ChatStore";     // 存入的列表数据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();     }     /**      * 请求分布式权限      */     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);         // 输入框内容变化监听         tfContent.addTextObserver((text, start, before, count) -> {              btnSend.setEnabled(text.length() != 0);         });         // 点击发送按钮         btnSend.setClickedListener(component -> {              String content = tfContent.getText().trim();             listData.add(new ChatDataBean(Tools.getDeviceId(mContext),picIndex,content));             // 存入数据库中             singleKvStore.putString(KEY_DATA, ZSONObject.toZSONString(listData));             // 清空输入框             tfContent.setText("");         });     }     /**      * 初始化分布式数据库      */     private void initDatabase() {          // 创建分布式数据库管理器         kvManager = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(this));         // 数据库配置         Options options = new Options();         options.setCreateIfMissing(true) // 设置数据库不存在时是否创建                 .setEncrypt(false) // 设置数据库是否加密                 .setKvStoreType(KvStoreType.SINGLE_VERSION); //数据库类型         // 创建分布式数据库         singleKvStore = kvManager.getKvStore(options, STORE_NAME);         // 监听数据库数据改变         singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, new KvStoreObserver() {              @Override             public void onChange(ChangeNotification changeNotification) {                  List<Entry> insertEntries = changeNotification.getInsertEntries();                 List<Entry> updateEntries = changeNotification.getUpdateEntries();                 // 第一次存入数据,获取insertEntries                 if(insertEntries.size()>0){                      for (Entry entry : 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);                             });                         }                     }                 }else if(updateEntries.size()>0){                      for (Entry entry : 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 (KvStoreException e) {              e.printStackTrace();             // 没有找到,首次进入             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": "多设备协同",         "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="数据: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> 

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 {      // 显示数据     private Text text;     // 分布式数据库管理器     private KvManager kvManager;     // 分布式数据库     private SingleKvStore singleKvStore;     // 数据库名称     private static final String STORE_NAME = "MyStore";     // 存入的数据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();     }      /**      * 请求分布式权限      */     private void requestPermission() {          if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) {              if (canRequestPermission(DISTRIBUTED_DATASYNC)) {                  requestPermissionsFromUser(new String[]{ DISTRIBUTED_DATASYNC}, 0);             }         }     }      /**      * 初始化分布式数据库      */     private void initDatabase() {          // 创建分布式数据库管理器         kvManager = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(this));          // 数据库配置         Options options = new Options();         options.setCreateIfMissing(true) // 设置数据库不存在时是否创建                 .setEncrypt(false) // 设置数据库是否加密                 .setKvStoreType(KvStoreType.SINGLE_VERSION); //数据库类型         // 创建分布式数据库         singleKvStore = kvManager.getKvStore(options, STORE_NAME);         // 监听数据库数据改变         singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, new KvStoreObserver() {              @Override             public void onChange(ChangeNotification changeNotification) {                  List<Entry> insertEntries = changeNotification.getInsertEntries();                 List<Entry> updateEntries = changeNotification.getUpdateEntries();                  // 第一次存入数据,获取insertEntries                 if (insertEntries.size() > 0) {                      for (Entry entry : insertEntries) {                          if (KEY_COUNT.equals(entry.getKey())) {                              // 回调为非UI线程,需要在UI线程更新UI                             getUITaskDispatcher().syncDispatch(() -> {                                  int count = entry.getValue().getInt();                                 text.setText("数据:"+count);                             });                         }                     }                 } else if (updateEntries.size() > 0) {                      for (Entry entry : updateEntries) {                          if (KEY_COUNT.equals(entry.getKey())) {                              // 回调为非UI线程,需要在UI线程更新UI                             getUITaskDispatcher().syncDispatch(() -> {                                  int count = entry.getValue().getInt();                                 text.setText("数据:"+count);                             });                         }                     }                 }             }         });      }      /**      * 初始化组件      */     private void initComponent() {          text = (Text) findComponentById(ResourceTable.Id_text);         Button button = (Button) findComponentById(ResourceTable.Id_button);          // 点击事件         button.setClickedListener(component -> {              try {                  int count = singleKvStore.getInt(KEY_COUNT);                 singleKvStore.putInt(KEY_COUNT, count + 1);             } catch (KvStoreException e) {                  e.printStackTrace();                 // 没有找到,首次进入                 if (e.getKvStoreErrorCode() == KvStoreErrorCode.KEY_NOT_FOUND) {                      int count = 0;                     singleKvStore.putInt(KEY_COUNT, count + 1);                 }             }         });     } } 

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

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

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

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

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

https://harmonyos.51cto.com

-->云服务器提供商

分享到:

滇ICP备2023006006号-16