OpenHarmony Preferences 本地持久化存储开发(API Version23 + 适配版)
摘要
Preferences 是 OpenHarmony 轻量键值持久化存储组件,用于保存小型配置数据,应用重启、设备关机后数据不会丢失,常与 AppStorage 全局内存状态搭配使用,实现「内存实时读写 + 磁盘永久保存」双缓存架构,适配登录缓存、主题偏好、设置开关、搜索历史、用户基础配置等轻量数据场景。API Version23 重构 Preferences 文件读写、多实例锁、异步回调、类型序列化逻辑,修复低版本存储写入丢失、并发读写错乱、布尔 / 数字读取默认值异常、多页面同时操作文件冲突等兼容缺陷。低版本工程升级至 API23 后,普遍出现:保存的数据重启应用消失、并发读写覆盖数据、读取数字返回 0、布尔值读取恒为 false、存储文件损坏等故障。本文基于 DevEco Studio 适配 OpenHarmony API23 及以上版本,讲解 Preferences 同步 / 异步读写、多类型存取、封装全局存储工具类、与 AppStorage 联动持久化、分页搜索历史存储,输出并发读写锁、存储性能优化、异常容错规范,汇总版本升级兼容故障解决方案,为鸿蒙轻量本地持久化开发提供标准化实操模板。
关键词
OpenHarmony;ArkUI;API Version23;Preferences;本地持久化;键值存储;持久化全局配置;AppStorage 联动;轻量缓存
一、引言
1.1 Preferences 开发背景
AppStorage 仅存在应用内存,进程杀死数据全部销毁,无法实现永久配置保存;数据库适合海量复杂数据,存储小型开关、用户名、主题标识会产生性能冗余。Preferences 作为系统原生轻量持久化方案,以 XML 文件形式持久化至应用沙盒目录,仅支持基础键值类型,读写速度快、API 简洁,是应用配置类数据首选存储方案。
OpenHarmony API Version23 针对 Preferences 底层文件 IO 引擎做全面升级,核心变更点:
- 新增文件读写互斥锁,同一存储文件多页面并发读写不再互相覆盖;
- 统一基础类型序列化规则,string/number/boolean 读取不会出现默认值错乱;
- 优化异步 getPreferences 加载逻辑,修复低版本文件加载延迟导致读取空值;
- 规范 flush 持久化强制落盘机制,区分内存缓存与磁盘持久化;
- 增加文件损坏自动兜底默认值逻辑,避免应用闪退;
- 限制超大字符串、数组直接存入 Preferences,给出性能告警。
大量 API9~11 旧项目升级后,切换深色模式重启失效、登录状态重启丢失、搜索历史保存不全,根源是旧版无锁并发写入、未强制 flush 落盘,因此掌握 API23 标准 Preferences 封装规范是配置类开发必备技能。
1.2 开发环境与测试场景
开发工具:DevEco Studio 5.0 及以上 适配系统:OpenHarmony API Version23、HarmonyOS NEXT 开发语言:ArkTS 导入模块:@ohos.data.preferences 测试场景:深色主题持久保存、登录状态本地缓存、用户昵称永久存储、搜索历史数组持久化、AppStorage 全局配置落地磁盘、多页面并发读写配置文件
二、API23+ Preferences 核心 API 与版本变更说明
2.1 核心对象获取方式(API23 标准异步写法)
ets
import preferences from '@ohos.data.preferences'
// 获取Preferences实例,fileName为沙盒内存储文件名
async function getPrefInstance() {
let dataPreferences = await preferences.getPreferences(getContext(this), "app_config")
return dataPreferences
}
2.2 数据写入与落盘
- putSync (key, value):同步写入内存缓存
- put (key, value):异步写入内存缓存
- flush ():强制将内存缓存数据写入磁盘文件(API23 必须调用,否则进程销毁丢失)
2.3 数据读取 API
getSync<T>(key, defaultValue) 同步读取;get<T>(key, defaultValue) 异步读取,无数据返回默认值。 支持类型:string、number、boolean、Array<string>
2.4 删除与清空
deleteSync (key) 删除单条键;clearSync () 清空全部存储;hasSync (key) 判断键是否存在。
2.5 API23 废弃与强制约束
- 废弃无 flush 直接退出进程写法,不执行 flush 会丢失本次写入;
- 禁止多实例同时操作同一个 fileName 文件,必须全局单例管理;
- 废弃复杂对象直接存储,对象需 JSON 序列化字符串后存取;
- 单条字符串存储长度上限 8000 字符,超长数据拆分或改用数据库;
- 同步 API 禁止在主线程循环大量调用,易造成页面卡顿。
三、API23 标准基础示例代码
3.1 基础布尔值持久化(深色模式开关)
ets
import preferences from '@ohos.data.preferences'
// 保存深色模式开关
async function saveDarkMode(isDark: boolean) {
let pref = await preferences.getPreferences(getContext(), "app_config")
pref.putSync("dark_mode", isDark)
await pref.flush() // API23必须强制落盘
}
// 读取深色模式,无数据默认false
async function getDarkMode(): Promise<boolean> {
let pref = await preferences.getPreferences(getContext(), "app_config")
let val = pref.getSync("dark_mode", false)
return val
}
3.2 字符串持久化(登录用户名)
ets
async function saveUserName(name: string) {
let pref = await preferences.getPreferences(getContext(), "app_config")
pref.putSync("user_name", name)
await pref.flush()
}
async function getUserName(): Promise<string> {
let pref = await preferences.getPreferences(getContext(), "app_config")
return pref.getSync("user_name", "游客")
}
3.3 数组存储(搜索历史,JSON 序列化)
ets
async function saveSearchHistory(list: string[]) {
let pref = await preferences.getPreferences(getContext(), "app_config")
let jsonStr = JSON.stringify(list)
pref.putSync("search_history", jsonStr)
await pref.flush()
}
async function getSearchHistory(): Promise<string[]> {
let pref = await preferences.getPreferences(getContext(), "app_config")
let jsonStr = pref.getSync("search_history", "[]")
return JSON.parse(jsonStr)
}
四、四大业务完整实战案例(全兼容 API23)
4.1 实战一:全局 Preferences 工具类单例封装(项目通用)
新建 utils/preference_utils.ets,全局统一存取,避免多实例冲突
ets
import preferences from '@ohos.data.preferences'
import common from '@ohos.app.ability.common'
class PreferenceUtil {
private static instance: PreferenceUtil
private pref: preferences.Preferences | null = null
private readonly FILE_NAME = "app_global_config"
static getInstance(): PreferenceUtil {
if (!PreferenceUtil.instance) {
PreferenceUtil.instance = new PreferenceUtil()
}
return PreferenceUtil.instance
}
// 初始化存储实例,页面启动调用一次
async init(context: common.UIAbilityContext) {
this.pref = await preferences.getPreferences(context, this.FILE_NAME)
}
// 保存布尔值
async putBool(key: string, value: boolean) {
if (!this.pref) return
this.pref.putSync(key, value)
await this.pref.flush()
}
async getBool(key: string, def: boolean = false): Promise<boolean> {
if (!this.pref) return def
return this.pref.getSync(key, def)
}
// 保存字符串
async putString(key: string, value: string) {
if (!this.pref) return
this.pref.putSync(key, value)
await this.pref.flush()
}
async getString(key: string, def: string = ""): Promise<string> {
if (!this.pref) return def
return this.pref.getSync(key, def)
}
// 保存数字
async putNumber(key: string, value: number) {
if (!this.pref) return
this.pref.putSync(key, value)
await this.pref.flush()
}
async getNumber(key: string, def: number = 0): Promise<number> {
if (!this.pref) return def
return this.pref.getSync(key, def)
}
// 数组序列化存储
async putArray<T>(key: string, arr: T[]) {
if (!this.pref) return
let str = JSON.stringify(arr)
this.pref.putSync(key, str)
await this.pref.flush()
}
async getArray<T>(key: string): Promise<T[]> {
if (!this.pref) return []
let str = this.pref.getSync(key, "[]")
return JSON.parse(str)
}
// 删除单条key
async deleteKey(key: string) {
if (!this.pref) return
this.pref.deleteSync(key)
await this.pref.flush()
}
// 清空全部存储
async clearAll() {
if (!this.pref) return
this.pref.clearSync()
await this.pref.flush()
}
}
export default PreferenceUtil.getInstance()
4.2 实战二:Preferences + AppStorage 联动持久化主题
实现:页面修改开关同步 AppStorage 内存,同时写入 Preferences 磁盘,应用重启自动读取 Preferences 回填全局状态
ets
import prefUtil from '../utils/preference_utils'
@Entry
@Component
struct ThemePage {
@StorageLink('darkMode') darkSwitch: boolean = false
async aboutToAppear() {
// 页面加载从本地持久化读取,初始化全局状态
await prefUtil.init(getContext(this))
let localDark = await prefUtil.getBool("dark_mode")
AppStorage.Set("darkMode", localDark)
this.darkSwitch = localDark
}
// 切换开关同步内存与本地存储
async changeTheme(val: boolean) {
this.darkSwitch = val
AppStorage.Set("darkMode", val)
await prefUtil.putBool("dark_mode", val)
}
build() {
Column({ space: 25 }) {
Text("持久化深色主题设置")
.fontSize(22)
.fontWeight(FontWeight.Bold)
Row() {
Text("夜间模式").layoutWeight(1).fontSize(17)
Toggle({ isOn: this.darkSwitch })
.onChange(async v => await this.changeTheme(v))
}
.width("100%")
.height(56)
.padding(15)
.backgroundColor(Color.White)
.borderRadius(10)
Text("关闭应用重新打开,配置不会丢失")
.fontSize(14)
.fontColor("#999")
}
.width("100%")
.height("100%")
.padding(20)
.backgroundColor(this.darkSwitch ? "#1A1A1A" : "#F5F5F5")
}
}
4.3 实战三:登录信息本地持久缓存(重启免登)
ets
import prefUtil from '../utils/preference_utils'
import router from '@ohos.router'
@Entry
@Component
struct LoginPage {
@State account: string = ""
@State pwd: string = ""
async aboutToAppear() {
await prefUtil.init(getContext(this))
// 读取上次登录账号回填输入框
let saveAccount = await prefUtil.getString("login_account")
this.account = saveAccount
}
async handleLogin() {
if (this.account.length < 1) {
promptAction.showToast({ message: "账号不能为空" })
return
}
// 登录成功存入本地持久化与全局AppStorage
await prefUtil.putString("login_account", this.account)
await prefUtil.putBool("is_login", true)
AppStorage.Set("isLogin", true)
AppStorage.Set("userName", this.account)
router.replaceUrl({ url: "pages/mine/mine" })
}
build() {
Column({ space: 22 }) {
Text("账号登录(持久化缓存)")
.fontSize(24)
.fontWeight(FontWeight.Bold)
TextInput({ text: this.account, placeholder: "输入账号" })
.width("100%")
.height(48)
.onChange(v => this.account = v)
TextInput({ text: this.pwd, placeholder: "输入密码" })
.type(InputType.Password)
.width("100%")
.height(48)
Button("登录并保存账号")
.width("100%")
.height(48)
.backgroundColor("#007DFF")
.onClick(async () => await this.handleLogin())
}
.width("100%")
.height("100%")
.padding(25)
.justifyContent(FlexAlign.Center)
}
}
4.4 实战四:搜索历史数组持久存取
ets
import prefUtil from '../utils/preference_utils'
@Entry
@Component
struct SearchPage {
@State keyword: string = ""
@State historyList: string[] = []
async aboutToAppear() {
await prefUtil.init(getContext(this))
// 读取本地历史记录
this.historyList = await prefUtil.getArray<string>("search_history")
}
// 新增搜索词并持久保存
async addHistory() {
if (!this.keyword) return
// 去重
let idx = this.historyList.indexOf(this.keyword)
if (idx > -1) this.historyList.splice(idx, 1)
this.historyList.unshift(this.keyword)
// 限制最多8条历史
if (this.historyList.length > 8) this.historyList.pop()
// 存入本地持久化
await prefUtil.putArray("search_history", this.historyList)
this.keyword = ""
}
build() {
Column({ space: 18 }) {
Row({ space: 10 }) {
TextInput({ text: this.keyword, placeholder: "输入搜索内容" })
.layoutWeight(1)
.height(44)
Button("搜索")
.height(44)
.onClick(async () => await this.addHistory())
}
Text("搜索历史").fontSize(18).fontWeight(FontWeight.Medium)
List({ space: 8 }) {
ForEach(this.historyList, (item: string) => {
ListItem() {
Text(item).width("100%").padding(12).backgroundColor(Color.White).borderRadius(8)
}
})
}
.layoutWeight(1)
}
.width("100%")
.height("100%")
.padding(15)
}
}
五、API23+ 持久化存储适配与性能优化规范
5.1 多页面并发读写规范
- 全局使用单例工具类管理 Preferences 实例,禁止每个页面新建实例;
- 每次 put 操作后必须执行 await flush () 强制落盘,API23 无自动持久化;
- 短时间连续多次写入增加防抖,避免高频 flush 重复 IO 操作;
- 启动页统一初始化 pref 实例,子页面直接调用工具类无需重复 init。
5.2 数据存储分层规范
- 临时页面变量:@State,页面销毁丢失;
- 全局内存共享配置:AppStorage,进程杀死丢失;
- 永久保存配置:Preferences,双缓存架构(AppStorage+Preferences);
- 海量结构化数据、图片二进制:使用 RDB 关系型数据库,不使用 Preferences。
5.3 性能优化准则
- 不存储超长文本、大型 JSON 对象,拆分精简字段;
- 主线程避免循环同步 get/put 大量数据,改用异步 API;
- 退出登录、重置功能调用 clearAll 清空冗余配置,减少文件体积;
- 数组统一 JSON 序列化存储,API23 不支持直接传入数组参数。
六、API23 升级高频兼容问题与解决方案
问题 1:重启应用后保存的配置全部消失 解决:每次写入后必须执行await pref.flush()强制写入磁盘,旧版本隐性落盘逻辑在 API23 已移除。
问题 2:多页面同时读写同一配置,数据互相覆盖错乱 解决:全局单例工具类统一管控实例,利用 API23 内置文件互斥锁,禁止多实例操作同一文件。
问题 3:读取布尔值恒为 false、数字恒为 0 解决:读取时传入正确默认值,旧项目升级统一替换同步 getSync,异步 get 需 await 接收返回。
问题 4:数组存入后读取解析报错 解决:复杂数组 / 对象必须 JSON.stringify 序列化字符串存储,读取后 JSON.parse 还原。
问题 5:页面频繁切换存储读写,页面滑动卡顿 解决:增加防抖延迟,合并短时间多次写入操作,减少 flush 磁盘 IO 次数。
问题 6:升级后旧存储文件读取失败、返回默认值 解决:初始化时增加异常捕获,文件损坏自动使用默认值覆盖重建配置文件。
七、总结
Preferences 是 OpenHarmony 轻量本地持久化标准组件,API Version23 重构文件 IO 并发锁、数据序列化、强制落盘机制,解决旧版数据丢失、并发错乱核心缺陷。项目标准架构为「Preferences 磁盘持久化 + AppStorage 全局内存缓存」,启动时从本地读取回填全局状态,修改时同步更新内存与磁盘,兼顾实时响应与永久保存。
更多推荐



所有评论(0)