OpenHarmony Preferences 本地持久化存储实战详解
一、前言
在 OpenHarmony 应用开发中,Preferences 偏好存储常用于保存轻量键值对数据:用户配置、登录状态、开关设置、缓存标识等,数据持久保存在本地,应用重启、设备关机后数据不丢失。相较于数据库,Preferences 使用简单、专注字符串 / 数字 / 布尔等基础类型,是项目高频本地存储方案。本篇完整讲解 API 用法、存取、删除、同步 / 异步操作,搭配落地代码。
依赖模块:
@ohos.data.preferences
二、核心基础概念
- Preferences 实例:以文件名区分数据库,一个文件对应一套独立键值数据;
- 存储数据类型:支持
string、number、boolean、Array<string>四种; - 数据落盘:写入数据后必须调用
flush()才会持久化写入磁盘,否则只在内存。
三、前置导入
ets
import preferences from '@ohos.data.preferences' import common from '@ohos.app.ability.common'获取上下文 Context(Ability 上下文,存储必备参数)。
四、基础 CRUD 案例
4.1 封装获取 Preferences 工具对象
ets
// 获取偏好存储实例 async function getPrefer(context: common.UIAbilityContext, fileName: string) { let prefer = await preferences.getPreferences(context, fileName) return prefer }4.2 写入 & 保存数据
ets
@Entry @Component struct PreWriteDemo { // 上下文 context = getContext(this) as common.UIAbilityContext async saveData() { // 打开userinfo.xml存储文件 let prefer = await getPrefer(this.context, "userinfo") // 存入多组键值 prefer.putSync("username", "Harmony开发者") prefer.putSync("age", 22) prefer.putSync("isLogin", true) prefer.putSync("hobby", ["编程", "嵌入式", "鸿蒙开发"]) // 关键:持久化落地磁盘 await prefer.flush() console.info("数据保存成功") } build() { Column() { Button("保存用户信息") .width(200) .onClick(() => this.saveData()) } .width("100%") .height("100%") .justifyContent(FlexAlign.Center) } }4.3 读取本地存储数据
ets
@Entry @Component struct PreReadDemo { @State name: string = "" @State age: number = 0 @State loginStat: boolean = false context = getContext(this) as common.UIAbilityContext async readData() { let prefer = await getPrefer(this.context, "userinfo") // 参数:键名、默认值(无数据时返回默认) this.name = prefer.getSync("username", "未知用户") this.age = prefer.getSync("age", 0) this.loginStat = prefer.getSync("isLogin", false) } build() { Column({ space: 15 }) { Button("读取存储数据").onClick(() => this.readData()) Text(`用户名:${this.name}`).fontSize(18) Text(`年龄:${this.age}`).fontSize(18) Text(`登录状态:${this.loginStat ? "已登录" : "未登录"}`).fontSize(18) } .padding(30) .width("100%") .height("100%") .justifyContent(FlexAlign.Center) } }4.4 删除指定键、清空全部数据
ets
@Entry @Component struct PreDelDemo { context = getContext(this) as common.UIAbilityContext // 删除单个key async delKey() { let prefer = await getPrefer(this.context, "userinfo") prefer.deleteSync("age") await prefer.flush() console.info("age字段删除完成") } // 清空当前文件所有数据 async clearAll() { let prefer = await getPrefer(this.context, "userinfo") prefer.clearSync() await prefer.flush() console.info("全部数据清空") } build() { Column({ space:20 }) { Button("删除age字段").onClick(()=>this.delKey()) Button("清空全部数据").onClick(()=>this.clearAll()) } .width("100%") .height("100%") .justifyContent(FlexAlign.Center) } }五、异步写法(Promise 方式,项目主流)
除了putSync/getSync同步 API,官方推荐异步 API 避免阻塞 UI 线程:
ets
async function asyncOpt(context: common.UIAbilityContext) { let prefer = await preferences.getPreferences(context, "setting") // 异步存 await prefer.put("nightMode", true) // 异步读 let res = await prefer.get("nightMode", false) console.info("夜间模式:" + res) await prefer.flush() }六、综合实战:应用设置页持久化开关
结合之前 Toggle 开关组件,实现开关状态永久保存,重启 APP 状态不变
ets
import preferences from '@ohos.data.preferences' import common from '@ohos.app.ability.common' @Component struct getPreferTool { static async getPre(context: common.UIAbilityContext, name: string) { return await preferences.getPreferences(context, name) } } @Entry @Component struct SettingStorePage { @State nightOpen: boolean = false @State notifyOpen: boolean = false context = getContext(this) as common.UIAbilityContext aboutToAppear() { // 页面加载读取本地存储 this.loadSetting() } // 读取配置 async loadSetting() { let pre = await getPreferTool.getPre(this.context, "app_setting") this.nightOpen = await pre.get("nightMode", false) this.notifyOpen = await pre.get("notify", true) } // 保存配置 async saveSetting() { let pre = await getPreferTool.getPre(this.context, "app_setting") await pre.put("nightMode", this.nightOpen) await pre.put("notify", this.notifyOpen) await pre.flush() } build() { Column({ space: 20 }) { Text("系统偏好设置").fontSize(22).fontWeight(FontWeight.Bold).margin({bottom:20}) Row() { Text("夜间模式").fontSize(18).layoutWeight(1) Toggle({ isOn: this.nightOpen }) .onChange((v: boolean) => { this.nightOpen = v this.saveSetting() }) } .width("100%") .padding(15) .backgroundColor("#fff") .borderRadius(8) Row() { Text("消息推送").fontSize(18).layoutWeight(1) Toggle({ isOn: this.notifyOpen }) .onChange((v: boolean) => { this.notifyOpen = v this.saveSetting() }) } .width("100%") .padding(15) .backgroundColor("#fff") .borderRadius(8) } .width("100%") .height("100%") .padding(20) .backgroundColor("#f5f5f5") } }效果:修改开关后自动落地本地,关闭应用再次打开,开关状态和上次一致。
七、开发使用规范与注意事项
- 适用场景
- ✅ 小型配置、登录标记、开关状态、用户简单信息
- ❌ 大批量数据、复杂结构化数据(改用关系型数据库 RDB)
- flush () 必写:所有修改操作后必须执行 flush,否则数据仅存在内存,卸载 / 重启丢失;
- 文件名规范:按业务拆分文件,用户数据 user.xml、配置 setting.xml,不要全部塞进同一个文件;
- 默认值:get 时必须设置兜底默认值,防止 key 不存在返回 undefined 导致页面报错。
