在开发跨设备协作文档应用时,最大的噩梦不是网络断开,而是两台设备分别在离线状态下修改了同一份文档。等它们重新联网同步时,后同步的数据直接覆盖了前面的数据,导致用户的修改凭空消失。为了彻底解决这个问题,我们不得不推翻默认的同步机制,重新设计一套底层的合并策略。

前置环境与隐形的通讯墙
鸿蒙的分布式数据管理(KVStore)底层依赖于软总线。很多开发者写完了代码跑不通,往往不是 API 用错了,而是环境没配对。
两台设备必须登录同一个华为账号,并且同时开启蓝牙和 Wi-Fi。最隐蔽的警示是,bundleName 必须与 KVManager 创建时传入的完全一致。由于系统对权限收得很紧,必须在配置文件中提前声明 ohos.permission.DISTRIBUTED_DATASYNC 权限,并且需要向用户动态申请。

时间戳机制带来的覆盖灾难
起初我以为系统底层会处理冲突。但仔细阅读文档发现,默认采用的是 Last-Write-Wins(最后写入者胜出)策略,基于设备本地时间戳。
这是一个巨大的隐患:不同设备的时间并非绝对同步。如果手机的时间比平板快了 5 分钟,那么在手机上的任何操作都会在未来 5 分钟内“死死压制”平板上的修改。
一旦发生冲突,用户的心血直接灰飞烟灭。

基于版本号的手动合并(CRDT)
为了掌控数据的主权,我们必须放弃默认的时间戳策略,在业务层引入版本号机制。

typescript

interface DocumentNode {
  id: string;
  content: string;
  version: number; // 核心:手动维护的版本号
}

当客户端监听到远端数据推送(dataChange)时,绝不直接覆盖本地 UI。而是先把远端的版本号和本地的版本号做对比。
如果远端版本大于本地,说明远端有更新,直接接受。如果远端版本等于本地版本,但内容不同,说明发生了并发写入冲突。此时必须触发预设的业务合并算法(比如把两段文本拼接,或者提示用户手动选择保留哪一份),合并完成后,将本地版本号加一,再重新推送到 KVStore。

单条数据大小的红线
在测试阶段,我们试图把一个包含几千条记录的富文本对象序列化后存入一个 Key 中。结果同步延迟极高,甚至引发了底层崩溃。
必须牢记:KVStore 单条数据不建议超过 1MB,整个库不要超过 10MB。如果是大对象,必须拆分成多个 Key 存储,或者直接走分布式文件系统。同时,记得在页面销毁前,调用 off('dataChange') 注销监听,否则会引发严重的内存泄漏。

准备两台设备,断开网络。在设备 A 上写一段话,在设备 B 上修改同一段话。同时联网后,用你写的版本号合并逻辑去拦截默认的覆盖行为,看看两边最终的数据是否都能保留下来。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐