HarmonyOS 5分布式数据同步实战:跨设备待办事项应用

news/2025/9/24 17:18:27/文章来源:https://www.cnblogs.com/xpzll/p/19109593

🔧 一、前期准备:配置与权限

在开始编码前,需要进行一些基础配置。

  1. 模块配置 (module.json5): 在 module.json5文件中申请分布式数据同步权限。

    {"module": {"requestPermissions": [{"name": "ohos.permission.DISTRIBUTED_DATASYNC"}]}
    }
    

    此权限允许应用在可信设备组网内同步数据。

  2. 导入模块: 在你的ArkTS文件中,导入必要的模块。

    import distributedKVStore from '@ohos.data.distributedKVStore';
    import deviceManager from '@ohos.distributedDeviceManager';
    import common from '@ohos.app.ability.common';
    import { BusinessError } from '@ohos.base';
    // UI相关组件
    import { TodoItem } from './TodoItem'; // 自定义数据模型,见下文
    

📊 二、定义数据模型

定义一个简单的待办事项数据模型,通常放在一个单独的文件中(如 TodoItem.ets)。

// TodoItem.ets
export class TodoItem {id: string; // 唯一标识,用于分布式同步content: string = ''; // 待办内容completed: boolean = false; // 完成状态createdAt: number = Date.now(); // 创建时间updatedAt: number = Date.now(); // 最后更新时间deviceId: string = ''; // 创建此条目的设备ID,用于显示来源constructor(content: string) {this.id = this.generateUUID(); // 生成唯一IDthis.content = content;}private generateUUID(): string {// 一个简单的UUID生成方法,实际项目中可使用更复杂的算法return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {const r = Math.random() * 16 | 0;const v = c == 'x' ? r : (r & 0x3 | 0x8);return v.toString(16);});}
}

为减少冲突,每条数据需有唯一标识。deviceIdupdatedAt有助于在冲突时决定保留哪条数据(例如采用“最后写入获胜”或合并策略)。

🧩 三、初始化分布式数据库

在应用的入口组件或一个单独的管理类中初始化分布式数据库。

// DistributedKVStoreManager.ets (示例)
class DistributedKVStoreManager {private kvManager: distributedKVStore.KVManager | null = null;private kvStore: distributedKVStore.SingleKVStore | null = null;private static instance: DistributedKVStoreManager;public static getInstance(): DistributedKVStoreManager {// 单例模式,确保全局只有一个数据库管理器实例if (!DistributedKVStoreManager.instance) {DistributedKVStoreManager.instance = new DistributedKVStoreManager();}return DistributedKVStoreManager.instance;}public async initKVStore(context: common.Context): Promise<void> {try {// 1. 创建KVManager配置const kvManagerConfig: distributedKVStore.Config = {bundleName: 'com.example.todoapp', // 你的应用包名userInfo: {userId: '0', // 同一用户ID下的设备可以同步数据userType: distributedKVStore.UserType.SAME_USER_ID}};// 2. 创建KVManager实例this.kvManager = distributedKVStore.createKVManager(kvManagerConfig);// 3. 配置KVStore选项const options: distributedKVStore.StoreConfig = {storeId: 'todo_app_store', // 存储标识kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,securityLevel: distributedKVStore.SecurityLevel.S2, // 安全等级autoSync: true, // 开启自动同步encrypt: false // 根据需求是否加密};// 4. 获取或创建KVStorethis.kvStore = await this.kvManager.getKVStore<distributedKVStore.SingleKVStore>(options);console.info('Distributed KVStore initialized successfully.');} catch (error) {console.error(`Failed to initialize KVStore: ${(error as BusinessError).message}`);}}public getKVStore(): distributedKVStore.SingleKVStore | null {return this.kvStore;}
}

autoSync: true使得数据变更会自动同步到同一用户下的所有设备。

🧩 四、核心数据操作与同步

在同一个管理类中,实现数据的增删改查和同步方法。

// 接 DistributedKVStoreManager.ets
class DistributedKVStoreManager {// ... 之前的代码 ...// 添加待办事项public async addTodoItem(todoItem: TodoItem): Promise<void> {if (!this.kvStore) {console.error('KVStore is not initialized.');return;}try {// 将TodoItem对象转换为JSON字符串存储const todoJson = JSON.stringify(todoItem);// 使用id作为Key,todoJson作为Value存入KVStoreawait this.kvStore.put(todoItem.id, todoJson);console.info(`Todo item added: ${todoItem.content}`);} catch (error) {console.error(`Failed to add todo item: ${(error as BusinessError).message}`);}}// 获取所有待办事项public async getAllTodoItems(): Promise<TodoItem[]> {if (!this.kvStore) {console.error('KVStore is not initialized.');return [];}try {const entries = await this.kvStore.getEntries('');const todoItems: TodoItem[] = [];for (let i = 0; i < entries.length; i++) {const itemJson = entries[i].value.value as string;try {const todoItem: TodoItem = JSON.parse(itemJson);todoItems.push(todoItem);} catch (parseError) {console.error(`Failed to parse todo item: ${parseError}`);}}return todoItems;} catch (error) {console.error(`Failed to get todo items: ${(error as BusinessError).message}`);return [];}}// 更新待办事项(例如标记完成/未完成)public async updateTodoItem(todoItem: TodoItem): Promise<void> {if (!this.kvStore) {console.error('KVStore is not initialized.');return;}try {todoItem.updatedAt = Date.now(); // 更新修改时间const todoJson = JSON.stringify(todoItem);await this.kvStore.put(todoItem.id, todoJson);console.info(`Todo item updated: ${todoItem.content}`);} catch (error) {console.error(`Failed to update todo item: ${(error as BusinessError).message}`);}}// 删除待办事项public async deleteTodoItem(todoId: string): Promise<void> {if (!this.kvStore) {console.error('KVStore is not initialized.');return;}try {await this.kvStore.delete(todoId);console.info(`Todo item deleted: ${todoId}`);} catch (error) {console.error(`Failed to delete todo item: ${(error as BusinessError).message}`);}}
}

📡 五、监听数据变化

为了在数据发生变化时(包括本地和远程设备)及时更新UI,需要注册数据变化监听器。

// 接 DistributedKVStoreManager.ets
class DistributedKVStoreManager {// ... 之前的代码 ...private dataChangeListener: distributedKVStore.DataChangeListener | null = null;public async setupDataChangeListener(callback: (changedItems: TodoItem[]) => void): Promise<void> {if (!this.kvStore) {return;}try {this.dataChangeListener = (data: distributedKVStore.ChangeData) => {console.info(`Data changed: key=${data.key}, value=${data.value?.value}`);// 当监听到变化,重新获取所有数据并回调更新UIthis.getAllTodoItems().then((items) => {callback(items);});};// 订阅所有类型的数据变更(添加、更新、删除)this.kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, this.dataChangeListener);} catch (error) {console.error(`Failed to set up data change listener: ${(error as BusinessError).message}`);}}// 在合适的地方(例如组件销毁时)移除监听器,防止内存泄漏public removeDataChangeListener(): void {if (this.kvStore && this.dataChangeListener) {this.kvStore.off('dataChange', this.dataChangeListener);this.dataChangeListener = null;}}
}

🖥️ 六、构建UI界面

最后,在UI组件(通常是 @Entry组件)中连接数据库管理和UI渲染。

// TodoListPage.ets
import { DistributedKVStoreManager } from '../model/DistributedKVStoreManager';
import { TodoItem } from '../model/TodoItem';@Entry
@Component
struct TodoListPage {@State todoList: TodoItem[] = [];@State newTodoContent: string = '';private kvStoreManager: DistributedKVStoreManager = DistributedKVStoreManager.getInstance();aboutToAppear() {// 初始化KVStorethis.kvStoreManager.initKVStore(getContext(this)).then(async () => {// 初始加载数据this.todoList = await this.kvStoreManager.getAllTodoItems();// 设置数据变化监听器await this.kvStoreManager.setupDataChangeListener((items) => {this.todoList = items;});});}aboutToDisappear() {// 移除监听器this.kvStoreManager.removeDataChangeListener();}build() {Column() {// 标题Text('跨设备待办事项').fontSize(30).margin(20)// 输入框和添加按钮Row() {TextInput({ placeholder: '输入新事项...', text: this.newTodoContent }).width('70%').onChange((value: string) => {this.newTodoContent = value;})Button('添加').width('30%').onClick(() => {if (this.newTodoContent.trim() !== '') {const newItem = new TodoItem(this.newTodoContent.trim());this.kvStoreManager.addTodoItem(newItem);this.newTodoContent = ''; // 清空输入框}})}.width('100%').padding(10)// 待办事项列表List({ space: 10 }) {ForEach(this.todoList, (item: TodoItem) => {ListItem() {Row() {// 完成状态复选框Checkbox().select(item.completed).onChange((checked: boolean) => {item.completed = checked;item.updatedAt = Date.now();this.kvStoreManager.updateTodoItem(item);})// 待办内容Text(item.content).fontSize(18).textDecoration(item.completed ? TextDecoration.LineThrough : TextDecoration.None).fontColor(item.completed ? '#999' : '#000')// 删除按钮Button('删除').onClick(() => {this.kvStoreManager.deleteTodoItem(item.id);})}.width('100%').justifyContent(FlexAlign.SpaceBetween)}}, (item: TodoItem) => item.id)}.layoutWeight(1) // 占据剩余空间.width('100%')}.height('100%').backgroundColor('#F5F5F5')}
}

💡 七、处理数据冲突

在分布式系统中,数据冲突(如多设备同时修改同一数据)不可避免。HarmonyOS分布式数据库默认采用“最后写入获胜”(LWW)策略,即时间戳最新的修改会覆盖旧数据。我们的 TodoItem模型中的 updatedAt字段正是用于比较时间先后。

对于更复杂的冲突解决策略(如合并特定字段),你可能需要在 DataChangeListener中获取变更数据后,手动比较本地和远程数据的 updatedAt字段,然后决定如何合并。

⚠️ 八、注意事项与最佳实践

  1. 性能: 单个KV记录的值不宜过大(建议小于500KB)。高频更新可考虑批处理操作。
  2. 错误处理: 务必对所有的数据库操作进行 try-catch,妥善处理可能出现的异常(如网络断开、同步失败)。
  3. 设备连接: 确保设备已登录同一华为账号,并在同一局域网内,且已在“设置”中形成可信组网。
  4. 离线支持: 应用应能在设备离线时正常进行本地增删改查,并在网络恢复后自动同步。
  5. 安全: 分布式数据在传输过程中会使用TLS进行加密。

通过以上步骤,你就可以构建一个功能完善的跨设备待办事项应用。HarmonyOS的分布式数据管理API大大简化了多设备同步的复杂性,让你能更专注于业务逻辑和用户体验。

需要参加鸿蒙认证的请点击 鸿蒙认证链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/916000.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解HarmonyOS 5的AVSession:构建跨设备媒体播放器

🎯 一、AVSession 概述与核心价值 AVSession(媒体会话)是HarmonyOS分布式媒体控制的核心框架。它允许应用程序将本地播放的媒体信息和控制能力暴露给系统,使得其他设备(如手机、平板、智慧屏)可以发现、查看和控…

Extjs小例子

Extjs小例子 1.监听文本框是否已经修改过xtype : textfield,  fieldLable : 标题,  listeners : {     change : function(field,newValue,oldValue){ alert(newValue+---+oldValue);  …

郑州网站建设怎么样短视频推广方案怎么做

随着半导体技术的不断进步&#xff0c;晶圆制造作为集成电路产业的核心环节&#xff0c;对生产过程的精密性和洁净度要求日益提高。在众多晶圆制造工具中&#xff0c;PFA&#xff08;全氟烷氧基&#xff09;晶圆夹以其独特的材质和性能&#xff0c;在近年来逐渐受到业界的广泛关…

HT-AD4PS-1+ 一分四射频功分器:1-500 MHz 小尺寸/低插损,通信、医疗全能打

HT-AD4PS-1+ 一分四射频功分器:1-500 MHz 小尺寸/低插损,通信、医疗全能打成都恒利泰(HenryTech)HT-AD4PS-1+ 是一款全国产化的一分四表贴功分器/合路器,频率覆盖 1-500 MHz,插入损耗≤1.8 dB,体积小巧,可直接…

HarmonyOS资源管理与访问:多分辨率与多语言适配

本文将深入探讨HarmonyOS应用开发中的资源管理机制,重点介绍多分辨率适配和多语言本地化的完整解决方案。1. 资源管理系统架构 HarmonyOS提供了统一的资源管理框架,支持应用资源的分类、访问和适配。资源管理系统采用…

面试官:为什么没有虚拟线程池?

Java 官方文档明确指出:Do not pool virtual threads. 虚拟线程不是昂贵资源,永远不应该被池化。 应该为每个任务创建一个新的虚拟线程,它们应该是短暂的、任务级别的。这是为什么呢?为什么只有虚拟线程 Virtual T…

做外国网站自媒体网络工程师和做网站哪个难

————— 第二天 —————————————————下面我们一起来研究这三个问题。问题1&#xff1a;哪些是需要回收的&#xff1f;首先我们需要知道如何哪些垃圾需要回收&#xff1f;判断对象是否需要回收有两种算法。一种是引用计数算法、一种是可达性分析算法。引用计…

润生软件简介:以“重构与共生”引领商业未来

2014年,广东企业家陈总敏锐洞察到:当算力实现百倍跃升,数字信息将深刻重塑社会结构,传统行业与企业形态面临全面重构。基于此,他发起创立了润生公司(Reconstruction-Symbiosis Framework,简称RS),开启一场以“…

Python 并发编程

Python 并发编程是提升程序执行效率的核心技术,尤其在处理多任务场景(如网络请求、数据计算、文件 IO 等)时至关重要。 1、threading与线程池 多线程是 Python 中最常用的并发方式之一,通过创建多个线程实现任务并…

博物馆展陈设计公司搜索引擎优化什么意思

hi&#xff0c;我是逸尘&#xff0c;一起学java吧 目标&#xff08;任务驱动&#xff09; 1.请重点的掌握I/O的。 场景&#xff1a;最近你在企业也想搞一个短视频又想搞一个存储的云盘&#xff0c;你一听回想到自己对于这些存储的基础还不是很清楚&#xff0c;于是回家开始了…

做液压的公司网站成都营销型网站建设中账号

文章目录 1. 命令概述2. 命令格式3. 常用选项4. 相关描述4.1 tree 命令安装 5. 参考示例5.1 创建树形目录5.2 使用 tree 命令查看树形目录 1. 命令概述 tree 命令用于在命令行界面以树状图形式显示目录及其子目录的内容。这个命令递归地列出所有子目录&#xff0c;并可选择显示…

安装pyautogui时与setuptool时冲突报错-module setuptools.dist has no attribute check_test_suite

采用离线的安装方式: 下载 命令: pip install E:\Codes\Wheels\PyAutoGUI-0.9.54.tar.gz --no-deps --target=..\myyolo1\Lib\site-packages

牛客周赛 Round 110 题解

View Post牛客周赛 Round 110 题解牛客周赛 Round 110 A 小苯的数字染色 ​ 手玩发现只有 \(n\) 为 \(1\) 不行。 void solve(){int n;cin >> n;if(n == 1){cout << "NO\n";}else{cout <<…

统计机器学习经典分类算法MATLAB实现

一、逻辑回归(Logistic Regression) 核心代码: % 加载数据(以鸢尾花数据集为例) load fisheriris; X = meas(:,1:2); % 选择前两个特征 Y = species;% 数据划分 cv = cvpartition(Y, HoldOut, 0.3); X_train = X(…

从安装到中文界面,一文带你玩转 DaVinci Resolve 20(零基础也能搞定)

软件介绍 DaVinci Resolve Studio v20.0.49是Blackmagic Design推出的专业影视后期制作软件,集成剪辑、调色、视觉特效、动态图形与音频后期功能于一体。该版本新增超100项创新功能,包括基于AI的UltraNR降噪工具、智…

靶场1

进入kali root权限反弹一个shell 攻击机监听: nc -lvnp 10000 目的主机: python3 drupa7-CVE-2018-7600.py http://210.26.72.210/drupal/ -c "bash -c bash -i >& /dev/tcp/210.26.72.230/10000 0>&…

昆明网站建设织梦外国客户网站

首先探讨一下为什么要使用nginx&#xff1a; 1、类似于apacheresin&#xff0c;nginx用于提供静态页面服务&#xff0c;比java服务器要强。虽然这些java服务器的性能都不赖&#xff0c;tomcat新版甚至还支持了epoll&#xff0c;但是用nginx来处理静态文件是一定比这些服务器更…

品牌茶业都在哪些网站做宣传潍坊网站建设方案咨询

事务的四个特征&#xff1a; 原子性 &#xff1a; 是指事务中包含的操作都被看做是一个逻辑单元 一致性&#xff1a; 开始前和结束后数据库都处于一致性状态 隔离性&#xff1a; 对数据库修改的多个事务是彼此隔离的 持久性&#xff1a; 事务完成之后对系统的影响是永久的

299、已凉

299、已凉299、已凉 唐●韩偓 碧阑干外绣帘垂,猩色屏风画折枝。 八尺龙须方锦褥,已凉天气未寒时。【现代诗意译】 翠绿栏杆外 绣帘低垂 猩红屏风 画着折枝花卉龙须八尺长 席上铺着锦绣被褥 天气已经凉了 还未到冷的时…

linux手动安装阿里云Logtail采集Nginx访问日志

这是一篇根据您提供的操作流程编写的技术文档。它详细记录了手动安装和配置Logtail以采集Nginx日志的全过程。技术文档:手动安装阿里云Logtail采集Nginx访问日志1. 文档概述 本文档详细描述了在Linux服务器上通过手动…