033-Preferences键值存储

📅 2026/7/18 0:45:24 👁️ 阅读次数 📝 编程学习
033-Preferences键值存储

Preferences 键值存储 — 轻量级配置数据的持久化方案

一、引言

在应用开发中,大量的配置类数据(如用户偏好、开关状态、简单缓存)不需要复杂的数据库支持,只需要一个轻量级的键值存储方案。鸿蒙系统的 Preferences(首选项)正是为此类场景设计,它以简洁的 API、异步的操作和良好的性能,成为配置数据持久化的首选方案。MoneyTrack 在提醒设置、预算金额等场景中大量使用 Preferences,实现了配置数据的快速读写和持久化。

二、核心知识点

2.1 Preferences 完整使用步骤

Preferences 的使用遵循「获取实例 → 读写数据 → 刷入磁盘」的标准流程:

import{preferences}from'@kit.ArkData'asyncfunctiondemoPreferences(context:Context){// 第一步:获取 Preferences 实例// getPreferences 是异步操作,返回 Preferences 对象// 文件名 'demo_pref' 对应磁盘上的一个 XML 文件constpref=awaitpreferences.getPreferences(context,'demo_pref')// 第二步:写入数据(修改在内存中,尚未落盘)awaitpref.put('username','alice')// stringawaitpref.put('age',25)// numberawaitpref.put('is_vip',true)// booleanawaitpref.put('tags',['premium','yearly'])// Array<string>// 第三步:刷入磁盘(必须显式调用 flush)// flush 将内存中的所有修改批量写入磁盘文件awaitpref.flush()// 读取数据(需指定默认值,防止首次读取返回 undefined)constusername=awaitpref.get('username','default_user')constage=awaitpref.get('age',18)constisVip=awaitpref.get('is_vip',false)}

关于 flush 的说明flush()是异步批量写入操作,调用后不保证立即完成。在应用进入后台或即将退出前调用flush()可确保数据安全。

2.2 异步读写流程

磁盘 XML内存缓存Preferences API应用层磁盘 XML内存缓存Preferences API应用层其他页面修改数据时getPreferences(context, name)读取 XML 文件返回数据加载到内存缓存返回 Preferences 实例put(key, value)更新内存缓存voidget(key, default)从内存读取valuevalueflush()批量写入磁盘写入完成voidon('change', callback)注册监听触发 change 回调

2.3 多实例隔离

Preferences 支持基于文件名创建多个独立实例,不同模块使用不同的文件,实现数据隔离:

// 不同模块使用独立的 Preferences 文件constreminderPref=awaitpreferences.getPreferences(context,'reminder_settings')constthemePref=awaitpreferences.getPreferences(context,'theme_settings')constbudgetPref=awaitpreferences.getPreferences(context,'budget_settings')// 每个文件独立存储,互不干扰awaitreminderPref.put('enabled',true)awaitthemePref.put('theme','dark')awaitbudgetPref.put('monthly_limit',5000)

多实例隔离的好处

  • 模块间数据解耦,修改一个模块的配置不影响其他模块
  • 文件粒度的管理,方便单独清除某个模块的缓存
  • 减少单个文件大小,提升读写性能

2.4 数据删除操作

除了读写,Preferences 还提供了数据删除能力:

// 删除指定的 key-valueawaitpref.delete('temp_setting')// 检查某个 key 是否存在consthasKey=awaitpref.has('reminder_enabled')// 清空所有数据(谨慎使用)awaitpref.clear()// 删除 Preferences 文件(释放磁盘空间)awaitpreferences.deletePreferences(context,'obsolete_settings')// 注意:delete 和 clear 后都需要 flush 才能持久化awaitpref.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 封装了提醒设置的全部逻辑:

exportclassReminderSettingVM{privatepref:preferences.Preferences|null=nullprivatecontext:Context// 持久化键值privatestaticreadonlyKEY_ENABLED='reminder_enabled'privatestaticreadonlyKEY_TIME='reminder_time'privatestaticreadonlyKEY_PERIOD='reminder_period'privatestaticreadonlyPREF_NAME='reminder_settings'constructor(context:Context){this.context=context}// 初始化:加载偏好设置asyncinit():Promise<void>{this.pref=awaitpreferences.getPreferences(this.context,ReminderSettingVM.PREF_NAME)// 注册监听this.pref.on('change',(key)=>{console.log('提醒设置变更:',key)})}// 读取提醒是否开启asyncisEnabled():Promise<boolean>{returnawaitthis.pref!.get(ReminderSettingVM.KEY_ENABLED,false)}// 设置提醒开关asyncsetEnabled(enabled:boolean):Promise<void>{awaitthis.pref!.put(ReminderSettingVM.KEY_ENABLED,enabled)awaitthis.pref!.flush()}// 读取提醒时间asyncgetReminderTime():Promise<string>{returnawaitthis.pref!.get(ReminderSettingVM.KEY_TIME,'08:00')}// 设置提醒时间asyncsetReminderTime(time:string):Promise<void>{awaitthis.pref!.put(ReminderSettingVM.KEY_TIME,time)awaitthis.pref!.flush()}}

3.2 预算金额持久化

在预算管理模块中,月度预算金额通过 Preferences 持久化:

// 键:budget_{year}_{month},支持分别存储每个月的预算asyncsaveMonthlyBudget(year:number,month:number,amount:number){constpref=awaitpreferences.getPreferences(this.context,'budget_settings')constkey=`budget_${year}_${month}`awaitpref.put(key,amount)awaitpref.flush()}asyncloadMonthlyBudget(year:number,month:number):Promise<number>{constpref=awaitpreferences.getPreferences(this.context,'budget_settings')constkey=`budget_${year}_${month}`returnawaitpref.get(key,0)}

3.3 使用注意事项

  1. 及时 flush:修改后调用flush()确保数据落盘,避免应用退出导致数据丢失
  2. 默认值:使用get()方法时始终提供合理的默认值,处理首次使用场景
  3. 键名规范:使用有意义的键名,如module_key的命名模式
  4. 数据量控制:Preferences 适合少量配置数据(建议不超过 100 个 key),大量数据应使用 RDB
  5. 避免频繁 flush:多次 put 后统一 flush 一次,减少磁盘 I/O

四、参考文档

  • Preferences 首选项指南
  • Preferences API 参考
  • 数据存储安全建议