本文分享 HarmonyOS 项目中使用 Preferences 存储 App 配置的最佳实践,从原生 API 的痛点出发,逐步演进为 singleton + sync API + 静默失败 + schema migration 的完整封装方案。
📝 详细摘要
作者以自身项目 breathing 中多语言持久化功能为起点,详细记录了使用 Preferences 存储配置时从直觉写法到生产级封装的完整思考过程。文章首先指出原生 API 的多个痛点:每次需要 async、到处传 context、返回值类型不安全、对象序列化重复代码、字符串常量散落等。然后围绕五个关键决策展开:1)全局 singleton 而非各模块独立持有,以控制初始化和 IO 成本;2)弃用 async 版 API,选用 sync 版(putSync/flushSync),因为 Preferences 操作基于内存 map,sync 版本省去 Promise 开销且不阻塞 UI;3)每个 getter 做 typeof 严格检查并返回 fallback,践行「静默失败哲学」—— 配置读取失败绝不让 App 挂掉;4)复杂对象全部序列化为 JSON 字符串走 setString/getString,保证可预测、可迁移、跨平台兼容;5)引入 schemaVersion + 迁移类 AppDataMigration,确保老用户升级时不会因字段变更而 crash 或丢数据。封装后的业务代码变成一行同步调用,无需关心 async、异常和 context。文章还解答了常见疑问:为何不用 dataAbility、崩溃时数据安全、iOS 版心智复用、性能影响等。最后给出三条建议:封装 singleton、优先用 sync、第一天就上 migration。
💡 主要观点
- 全局 singleton 持有一个 Preferences 实例,避免重复 IO 和不可控的初始化时机。 每个模块自己 getPreferences 会导致多次文件 IO 和异步依赖;全局 singleton 在 App 启动阶段 init,之后所有读写同步且无需传 context。
💬 文章金句
- init 里那个 initializing 状态很重要 —— 如果多个地方并发调 init,我不希望重复 getPreferences,也不希望第二个 caller 拿不到实例。
- 之后就改成了 put 完立刻 flush,宁愿多写几次盘,也不能让用户改完的设置丢。
- 配置读取失败绝不能让 App 挂掉,最多是回到默认值。
- 我推荐每个非玩具项目从第一天就上 schema version + migration 机制。上线之后再想加就晚了 —— 你不知道用户 Preferences 里都残留着什么祖传字段。
📊 文章信息
AI 初评:88
来源:掘金本周最热
作者:SameX
分类:软件编程
语言:中文
阅读时间:17 分钟
字数:4135
标签: HarmonyOS, 数据持久化, Singleton, 移动开发, TypeScript