033-Preferences键值存储
·
Preferences 键值存储 — 轻量级配置数据的持久化方案
一、引言
在应用开发中,大量的配置类数据(如用户偏好、开关状态、简单缓存)不需要复杂的数据库支持,只需要一个轻量级的键值存储方案。鸿蒙系统的 Preferences(首选项)正是为此类场景设计,它以简洁的 API、异步的操作和良好的性能,成为配置数据持久化的首选方案。MoneyTrack 在提醒设置、预算金额等场景中大量使用 Preferences,实现了配置数据的快速读写和持久化。
二、核心知识点
2.1 Preferences 完整使用步骤
Preferences 的使用遵循「获取实例 → 读写数据 → 刷入磁盘」的标准流程:
import { preferences } from '@kit.ArkData'
async function demoPreferences(context: Context) {
// 第一步:获取 Preferences 实例
// getPreferences 是异步操作,返回 Preferences 对象
// 文件名 'demo_pref' 对应磁盘上的一个 XML 文件
const pref = await preferences.getPreferences(context, 'demo_pref')
// 第二步:写入数据(修改在内存中,尚未落盘)
await pref.put('username', 'alice') // string
await pref.put('age', 25) // number
await pref.put('is_vip', true) // boolean
await pref.put('tags', ['premium', 'yearly']) // Array<string>
// 第三步:刷入磁盘(必须显式调用 flush)
// flush 将内存中的所有修改批量写入磁盘文件
await pref.flush()
// 读取数据(需指定默认值,防止首次读取返回 undefined)
const username = await pref.get('username', 'default_user')
const age = await pref.get('age', 18)
const isVip = await pref.get('is_vip', false)
}
关于 flush 的说明:flush() 是异步批量写入操作,调用后不保证立即完成。在应用进入后台或即将退出前调用 flush() 可确保数据安全。
2.2 异步读写流程
2.3 多实例隔离
Preferences 支持基于文件名创建多个独立实例,不同模块使用不同的文件,实现数据隔离:
// 不同模块使用独立的 Preferences 文件
const reminderPref = await preferences.getPreferences(context, 'reminder_settings')
const themePref = await preferences.getPreferences(context, 'theme_settings')
const budgetPref = await preferences.getPreferences(context, 'budget_settings')
// 每个文件独立存储,互不干扰
await reminderPref.put('enabled', true)
await themePref.put('theme', 'dark')
await budgetPref.put('monthly_limit', 5000)
多实例隔离的好处:
- 模块间数据解耦,修改一个模块的配置不影响其他模块
- 文件粒度的管理,方便单独清除某个模块的缓存
- 减少单个文件大小,提升读写性能
2.4 数据删除操作
除了读写,Preferences 还提供了数据删除能力:
// 删除指定的 key-value
await pref.delete('temp_setting')
// 检查某个 key 是否存在
const hasKey = await pref.has('reminder_enabled')
// 清空所有数据(谨慎使用)
await pref.clear()
// 删除 Preferences 文件(释放磁盘空间)
await preferences.deletePreferences(context, 'obsolete_settings')
// 注意:delete 和 clear 后都需要 flush 才能持久化
await pref.flush()
2.5 数据变更监听
Preferences 支持通过 on('change') 事件监听数据变更,这在多页面共享同一配置时特别有用——当某个页面修改了配置,其他页面可以实时感知变化并更新 UI:
preferences.on('change', (key) => {
if (key === 'reminder_enabled') {
this.refreshUI()
}
})
三、项目代码案例
3.1 ReminderSettingVM 完整实现
在 products/entry/src/main/ets/viewmodel/reminder/ReminderSettingVM.ets 中,ReminderSettingVM 封装了提醒设置的全部逻辑:
export class ReminderSettingVM {
private pref: preferences.Preferences | null = null
private context: Context
// 持久化键值
private static readonly KEY_ENABLED = 'reminder_enabled'
private static readonly KEY_TIME = 'reminder_time'
private static readonly KEY_PERIOD = 'reminder_period'
private static readonly PREF_NAME = 'reminder_settings'
constructor(context: Context) {
this.context = context
}
// 初始化:加载偏好设置
async init(): Promise<void> {
this.pref = await preferences.getPreferences(this.context, ReminderSettingVM.PREF_NAME)
// 注册监听
this.pref.on('change', (key) => {
console.log('提醒设置变更:', key)
})
}
// 读取提醒是否开启
async isEnabled(): Promise<boolean> {
return await this.pref!.get(ReminderSettingVM.KEY_ENABLED, false)
}
// 设置提醒开关
async setEnabled(enabled: boolean): Promise<void> {
await this.pref!.put(ReminderSettingVM.KEY_ENABLED, enabled)
await this.pref!.flush()
}
// 读取提醒时间
async getReminderTime(): Promise<string> {
return await this.pref!.get(ReminderSettingVM.KEY_TIME, '08:00')
}
// 设置提醒时间
async setReminderTime(time: string): Promise<void> {
await this.pref!.put(ReminderSettingVM.KEY_TIME, time)
await this.pref!.flush()
}
}
3.2 预算金额持久化
在预算管理模块中,月度预算金额通过 Preferences 持久化:
// 键:budget_{year}_{month},支持分别存储每个月的预算
async saveMonthlyBudget(year: number, month: number, amount: number) {
const pref = await preferences.getPreferences(this.context, 'budget_settings')
const key = `budget_${year}_${month}`
await pref.put(key, amount)
await pref.flush()
}
async loadMonthlyBudget(year: number, month: number): Promise<number> {
const pref = await preferences.getPreferences(this.context, 'budget_settings')
const key = `budget_${year}_${month}`
return await pref.get(key, 0)
}
3.3 使用注意事项
- 及时 flush:修改后调用
flush()确保数据落盘,避免应用退出导致数据丢失 - 默认值:使用
get()方法时始终提供合理的默认值,处理首次使用场景 - 键名规范:使用有意义的键名,如
module_key的命名模式 - 数据量控制:Preferences 适合少量配置数据(建议不超过 100 个 key),大量数据应使用 RDB
- 避免频繁 flush:多次 put 后统一 flush 一次,减少磁盘 I/O
四、参考文档
更多推荐



所有评论(0)