Preferences 多进程丢数据,降频 flush 也救不了整文件覆盖
两个 UIAbility 跑在独立进程里,一个写“最后浏览位置”,一个写“主题语言”。单独测都正常,一起跑就频繁丢数据,而且没有规律。你 await 了每一次 put 和 flush,返回值全是成功,日志里干干净净。
官方文档的原话是“首选项无法保证进程并发安全,会有文件损坏和数据丢失的风险,不支持在多进程场景下使用”。措辞不是“不建议”,是“不支持”。这意味着你问“把 flush 频率降到只在页面退出时写一次能不能规避”,答案是不能。两个进程各自持有一份全量内存快照,flush 是整文件覆盖写,即使写入时间错开,后写的进程也会把先写进程的字段整体回滚掉。丢数据不是概率问题,是机制问题。
RelationalStore 是默认的替代路径
多进程共享配置,最稳的迁移方向是关系型数据库。RDB 底层是 SQLite,多进程访问同一个数据库文件由数据库自身的锁机制保证一致性,各进程各自 getRdbStore 即可,不需要应用侧再套一层文件锁。配置项可以用一张两列的表 key / value 存,也可以按配置域分表,取决于后续查询模式。不要因为“它是键值形态”就硬留在 Preferences 里。
GSKV 模式是一个有版本门槛的折中
API 18 起 Preferences 新增了 GSKV 存储模式,支持多进程并发读写,数据实时落盘,不再走“先写内存再 flush”的 XML 整文件覆盖路径。落地前先用 isStorageTypeSupported 探测当前设备是否支持,支持再用 storageType 指定模式;跨进程变更订阅要从 change 换成 multiProcessChange,否则你在 A 进程改完,B 进程的监听根本不触发。
typescript
const options: preferences.Options = {
name: 'settings',
storageType: preferences.StorageType.GSKV
}
const store = await preferences.getPreferences(context, options)
store.on('multiProcessChange', (key: string) => {
// 其他进程改了同一个 key
})
不满足 API 18 的设备,不要用默认 XML 模式硬扛多进程。把写操作收敛到一个 Ability 里、其他进程通过 call 或公共事件请求写入,听起来能绕开,但那个“唯一写进程”被回收时,请求会静默丢失,兜底逻辑比直接换 RDB 复杂得多。
更多推荐

所有评论(0)