公司最近在攻坚一个家庭协作类应用,核心卖点是"多端同步"。手机上加了个买菜清单,平板上能立刻看到并勾选。为了实现这个功能,我们深入了 HarmonyOS 的分布式数据管理(KVStore),这其中的网络玄学和时间戳陷阱,简直让人抓狂。
环境配置的隐形拦截
照着文档写完代码后,在模拟器上跑得飞起,一到真机就彻底歇菜。两台设备死活发现不了对方。
这里有一个必须牢记的警示:分布式软总线对环境有极其严苛的要求。两台设备必须登录同一个华为账号,并且必须处于同一局域网,或者蓝牙处于可发现状态。此外,如果你在 module.json5 里漏配了 ohos.permission.DISTRIBUTED_DATASYNC 权限,系统会静默拦截你的所有同步请求,连报错都不会给你。
时间戳引发的覆盖惨案
最初的版本,我们使用了系统默认的同步策略:基于时间戳的最后写入者胜出(Last-Write-Wins)。
用户用手机把"买白菜"改成了"买牛肉",结果平板上离线状态下的修改(比如把时间猜错了)一同步,直接把牛肉覆盖回了白菜。用户气得直接投诉。
这是因为不同设备的系统时间并非绝对同步的。我们必须在业务代码层,抛弃系统时间,自己维护一套版本号机制。
typescript
interface ListItem {
id: string;
content: string;
isDone: boolean;
version: number; // 核心:手动维护的版本号
}
async function handleRemoteChange(remoteData: ListItem) {
const localData = getLocalData(remoteData.id);
if (remoteData.version > localData.version) {
// 接受远端更新
saveToDb(remoteData);
} else if (remoteData.version === localData.version) {
// 警示:版本相同但内容不同,发生并发冲突!
// 业务层合并(比如把内容拼起来)
const mergedData = { ...remoteData, version: localData.version + 1 };
saveToDb(mergedData);
// 推回远端
kvStore.put(remoteData.id, mergedData);
}
}
KVStore 的数据容量红线
为了图省事,我们一开始把整个清单数组序列化成一个巨大的 JSON 字符串,塞进了一个 Key 里。结果数据量大了一点之后,同步经常超时,甚至导致进程被系统杀掉。
必须明确:KVStore 单条数据绝对不能超过 1MB。正确的数据结构,应该把每一个清单项拆分成独立的 Key(如 item_123),这样不仅同步快,还能实现细粒度的更新,大大降低了带宽消耗和合并冲突的概率。
监听器的内存反噬
在页面里为了实时刷新 UI,我们使用了 on('dataChange') 去监听远端变化。但如果页面销毁时,你忘了调用 off('dataChange'),底层的回调依然会源源不断地向主线程发送消息。切十几个页面后,内存直接爆掉。必须严格把 on 和 off 放在 aboutToAppear 和 aboutToDisappear 中配对使用。
准备两台手机,装好你的应用。在断开网络的情况下,在设备 A 上添加一条记录,在设备 B 上添加另一条。同时联网。观察最终的数据是否两条都在。如果没有,说明你的合并逻辑有缺陷,去尝试修复它。