您现在的位置是:亿华云 > IT科技
HarmonyOS 分布式之聊天室应用
亿华云2025-10-08 21:19:05【IT科技】0人已围观
简介想了解更多内容,请访问:和华为官方合作共建的鸿蒙技术社区https://harmonyos.51cto.com介绍之前给大家介绍过【#星光计划1.0# 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
很赞哦!(49)
相关文章
- 互联网其实拼的也是人脉,域名投资也是一个时效性很强的东西,一个不起眼的消息就会引起整个域名投资市场的动荡,因此拓宽自己的人脉圈,完善自己的信息获取渠道,让自己能够掌握更为多样化的信息,这样才更有助于自己的域名投资。
- 腾讯敏捷协作平台TAPD发布5.0版本 助力企业实现一体化、数字化研发
- 让天下没有难用的搜索:阿里搜索如何成长为贴心“暖男”?
- 8个能提高Django开发效率的Python包
- 比较短的域名方便用户记忆和传播,它带来的好处往往会超过其他类型的域名,如果你非要域名短而且还要包含关键词,那么往往会事与愿违,现在这种域名基本上是可遇而不可求的。
- 让Docker日臻完善的8个优秀工具
- 关于负载均衡的一切
- 前端程序员不知道的14个JavaScript调试技巧,你知道几个?
- 因为域名解析需要同步到DNS根服务器,而DNS根服务器会不定时刷,只有DNS根服务器刷新后域名才能正常访问,新增解析一般会在10分钟左右生效,最长不会超过24小时,修改解析时间会稍微延长。
- 如何优雅的处理异常?SpringBoot全局异常与数据校验
站长推荐
前面这两个步骤都是在本机完成的。到这里还没有涉及真正的域名解析服务器,如果在本机中仍然无法完成域名的解析,就会真正请求域名服务器来解析这个域名了。
这份有原理、有代码、有Demo的算法资源火了!GitHub上超过2900星
5个Vuex插件,让你下一个VueJS项目开发速度提升3倍
微软开放6万项Linux专利背后,我们该注意什么?
在数以亿计的网站中,我们应该抓住每一个可能带来宣传的机会,域名可以带有企业的名字,一般可以使用汉语拼音或者英语单词或者是相关缩写的形式,只要用户记住了你企业的名字,就能很容易的打出你的网站域名,同样的,记住了网站域名也能很快的记住你公司的名字。
谷歌超200名工程师组织罢工 抗议公司包庇“安卓之父”
感谢师哥!一个正则表达式居然可以给我分享的这么详细!
熟练掌握JavaScript函数这四种方法,离javaScript高手又进一步!