news 2026/7/8 1:18:53

OpenHarmony Preferences 本地持久化存储开发(API Version23 + 适配版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 引擎做全面升级,核心变更点:

  1. 新增文件读写互斥锁,同一存储文件多页面并发读写不再互相覆盖;
  2. 统一基础类型序列化规则,string/number/boolean 读取不会出现默认值错乱;
  3. 优化异步 getPreferences 加载逻辑,修复低版本文件加载延迟导致读取空值;
  4. 规范 flush 持久化强制落盘机制,区分内存缓存与磁盘持久化;
  5. 增加文件损坏自动兜底默认值逻辑,避免应用闪退;
  6. 限制超大字符串、数组直接存入 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 数据写入与落盘

  1. putSync (key, value):同步写入内存缓存
  2. put (key, value):异步写入内存缓存
  3. 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 废弃与强制约束

  1. 废弃无 flush 直接退出进程写法,不执行 flush 会丢失本次写入;
  2. 禁止多实例同时操作同一个 fileName 文件,必须全局单例管理;
  3. 废弃复杂对象直接存储,对象需 JSON 序列化字符串后存取;
  4. 单条字符串存储长度上限 8000 字符,超长数据拆分或改用数据库;
  5. 同步 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 多页面并发读写规范

  1. 全局使用单例工具类管理 Preferences 实例,禁止每个页面新建实例;
  2. 每次 put 操作后必须执行 await flush () 强制落盘,API23 无自动持久化;
  3. 短时间连续多次写入增加防抖,避免高频 flush 重复 IO 操作;
  4. 启动页统一初始化 pref 实例,子页面直接调用工具类无需重复 init。

5.2 数据存储分层规范

  1. 临时页面变量:@State,页面销毁丢失;
  2. 全局内存共享配置:AppStorage,进程杀死丢失;
  3. 永久保存配置:Preferences,双缓存架构(AppStorage+Preferences);
  4. 海量结构化数据、图片二进制:使用 RDB 关系型数据库,不使用 Preferences。

5.3 性能优化准则

  1. 不存储超长文本、大型 JSON 对象,拆分精简字段;
  2. 主线程避免循环同步 get/put 大量数据,改用异步 API;
  3. 退出登录、重置功能调用 clearAll 清空冗余配置,减少文件体积;
  4. 数组统一 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 全局内存缓存」,启动时从本地读取回填全局状态,修改时同步更新内存与磁盘,兼顾实时响应与永久保存。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 1:16:48

三菱 FX2N PLC 步进电机驱动机械手:从I/O分配、梯形图到GX Works2仿真实战

三菱 FX2N PLC 步进电机驱动机械手&#xff1a;从I/O分配、梯形图到GX Works2仿真实战1. 项目背景与硬件配置在工业自动化领域&#xff0c;机械手的精准控制一直是核心课题。三菱FX2N系列PLC凭借其稳定的性能和丰富的扩展模块&#xff0c;成为中小型自动化项目的首选控制器。本…

作者头像 李华
网站建设 2026/7/8 1:14:44

15个实用的命令行工具,提升效率

15个实用的命令行工具&#xff0c;提升效率 # 15个实用的命令行工具&#xff0c;大幅提升你的开发效率 作为程序员&#xff0c;命令行是我们的第二战场。掌握一些实用的命令行工具&#xff0c;能让你的开发效率提升一个档次。下面就来盘点15个高效实用的命令行工具。 ## 1. fd …

作者头像 李华
网站建设 2026/7/8 1:14:11

java核心基础:第四章:对象和类

摘要&#xff1a;这篇笔记围绕 Java 面向对象编程的核心概念展开&#xff0c;涵盖四大特征&#xff08;封装、继承、多态、抽象&#xff09;、new 操作符与静态方法的区别、封装机制&#xff08;private / setter / getter&#xff09;的安全性问题&#xff0c;特别深入讨论了引…

作者头像 李华
网站建设 2026/7/8 1:11:40

如何确认 defconfig 中的配置项最终是否生效

如何确认 defconfig 中的配置项最终是否生效 作者&#xff1a;吴思含&#xff08;Witheart&#xff09;更新时间&#xff1a;20260507方法 查看内核根目录下的.config即可&#xff0c;.config是最终生效的方案。 defconfig 更像是一份“愿望清单”&#xff0c;而编译生成的 .co…

作者头像 李华
网站建设 2026/7/8 1:10:47

AI 辅助理解 Rust 泛型:让模型用具体类型举例,再抽象回泛型

AI 辅助理解 Rust 泛型&#xff1a;让模型用具体类型举例&#xff0c;再抽象回泛型 一、泛型这个坎&#xff0c;自学绕不过去 学 Rust 的过程中&#xff0c;泛型是我卡得最久的一个概念。 不是说完全看不懂——看别人的代码知道 <T> 大概在干什么&#xff0c;但轮到自己写…

作者头像 李华