Harmony开发之轻量级数据存储——Preferences实战
Harmony开发之轻量级数据存储——Preferences实战
引入:用户设置的持久化保存
在日常应用开发中,我们经常需要保存用户的个性化设置,比如主题颜色、字体大小、通知开关等。这些数据虽然量不大,但需要在应用重启后依然保持有效。HarmonyOS提供的Preferences(用户首选项)正是解决这类问题的轻量级数据存储方案。
一、Preferences核心概念
什么是Preferences?
Preferences是HarmonyOS提供的轻量级键值对存储方案,具有以下特点:
- 键值对存储:采用Key-Value形式,简单高效
- 数据类型支持:支持数字、字符串、布尔值及其数组类型
- 持久化存储:数据自动保存到应用沙箱,重启后依然存在
- 轻量级设计:适合存储用户配置、应用设置等少量数据
适用场景
- 用户个性化设置(主题、语言等)
- 应用配置信息
- 用户偏好记录
- 简单的状态保存
二、基础使用:增删改查
1. 导入模块与获取实例
// 文件:EntryAbility.ets
import { preferences } from '@kit.ArkData';
import { BusinessError } from '@kit.BasicServicesKit';
export default class EntryAbility extends UIAbility {
private pref: preferences.Preferences | null = null;
onWindowStageCreate(windowStage: window.WindowStage) {
// 获取Preferences实例
preferences.getPreferences(this.context, 'myAppPrefs')
.then((pref) => {
this.pref = pref;
console.info('Preferences实例获取成功');
})
.catch((err: BusinessError) => {
console.error(`获取Preferences失败: ${err.code}, ${err.message}`);
});
}
}
2. 写入数据
// 文件:pages/SettingsPage.ets
@Component
struct SettingsPage {
@State darkMode: boolean = false;
@State fontSize: number = 16;
// 保存设置
async saveSettings() {
try {
const pref = await preferences.getPreferences(getContext(this), 'myAppPrefs');
await pref.put('darkMode', this.darkMode);
await pref.put('fontSize', this.fontSize);
await pref.flush(); // 必须调用flush才能持久化
console.info('设置保存成功');
} catch (err) {
console.error('保存设置失败', err);
}
}
build() {
Column() {
Toggle({ type: ToggleType.Switch, isOn: this.darkMode })
.onChange((value: boolean) => {
this.darkMode = value;
this.saveSettings();
})
Slider({ value: this.fontSize, min: 12, max: 32 })
.onChange((value: number) => {
this.fontSize = value;
this.saveSettings();
})
}
}
}
3. 读取数据
// 文件:pages/Index.ets
@Entry
@Component
struct Index {
@State darkMode: boolean = false;
@State fontSize: number = 16;
aboutToAppear() {
this.loadSettings();
}
async loadSettings() {
try {
const pref = await preferences.getPreferences(getContext(this), 'myAppPrefs');
this.darkMode = await pref.get('darkMode', false);
this.fontSize = await pref.get('fontSize', 16);
} catch (err) {
console.error('读取设置失败', err);
}
}
build() {
Column() {
Text('当前主题: ' + (this.darkMode ? '深色' : '浅色'))
Text('字体大小: ' + this.fontSize)
}
.backgroundColor(this.darkMode ? '#333' : '#FFF')
.fontColor(this.darkMode ? '#FFF' : '#000')
.fontSize(this.fontSize)
}
}
4. 删除数据
// 删除单个键值对
async deleteKey(key: string) {
const pref = await preferences.getPreferences(getContext(this), 'myAppPrefs');
await pref.delete(key);
await pref.flush();
}
// 清空所有数据
async clearAll() {
const pref = await preferences.getPreferences(getContext(this), 'myAppPrefs');
await pref.clear();
await pref.flush();
}
三、数据变更订阅
Preferences支持数据变更监听,当数据发生变化时可以触发回调:
// 文件:pages/SettingsPage.ets
@Component
struct SettingsPage {
private pref: preferences.Preferences | null = null;
aboutToAppear() {
this.initPreferences();
}
async initPreferences() {
this.pref = await preferences.getPreferences(getContext(this), 'myAppPrefs');
// 订阅数据变更
this.pref.on('change', (key: string) => {
console.info(`数据发生变化: ${key}`);
// 可以在这里更新UI或执行其他操作
});
}
aboutToDisappear() {
// 取消订阅,避免内存泄漏
if (this.pref) {
this.pref.off('change');
}
}
}
四、工具类封装
为了提高代码复用性,建议对Preferences进行封装:
// 文件:utils/PreferencesUtils.ts
import { preferences } from '@kit.ArkData';
import { BusinessError } from '@kit.BasicServicesKit';
type ValueType = number | string | boolean | Array<number> | Array<string> | Array<boolean>;
class PreferencesUtils {
private static instance: PreferencesUtils;
private pref: preferences.Preferences | null = null;
static getInstance(): PreferencesUtils {
if (!PreferencesUtils.instance) {
PreferencesUtils.instance = new PreferencesUtils();
}
return PreferencesUtils.instance;
}
// 初始化Preferences
async init(context: common.Context, name: string = 'appPrefs'): Promise<void> {
try {
this.pref = await preferences.getPreferences(context, name);
} catch (err) {
const error = err as BusinessError;
console.error(`初始化Preferences失败: ${error.code}, ${error.message}`);
throw err;
}
}
// 保存数据
async put(key: string, value: ValueType): Promise<void> {
if (!this.pref) {
throw new Error('Preferences未初始化');
}
await this.pref.put(key, value);
await this.pref.flush();
}
// 读取数据
async get<T extends ValueType>(key: string, defaultValue: T): Promise<T> {
if (!this.pref) {
return defaultValue;
}
return await this.pref.get(key, defaultValue) as T;
}
// 检查是否包含某个key
async has(key: string): Promise<boolean> {
if (!this.pref) {
return false;
}
return await this.pref.has(key);
}
// 删除数据
async delete(key: string): Promise<void> {
if (!this.pref) {
return;
}
await this.pref.delete(key);
await this.pref.flush();
}
// 清空所有数据
async clear(): Promise<void> {
if (!this.pref) {
return;
}
await this.pref.clear();
await this.pref.flush();
}
}
export default PreferencesUtils.getInstance();
五、实战案例:主题设置
// 文件:pages/ThemeSetting.ets
import PreferencesUtils from '../utils/PreferencesUtils';
@Entry
@Component
struct ThemeSetting {
@State currentTheme: string = 'light';
@State fontSize: number = 16;
aboutToAppear() {
this.loadSettings();
}
async loadSettings() {
try {
this.currentTheme = await PreferencesUtils.get('theme', 'light');
this.fontSize = await PreferencesUtils.get('fontSize', 16);
} catch (err) {
console.error('读取设置失败', err);
}
}
async saveTheme(theme: string) {
try {
await PreferencesUtils.put('theme', theme);
this.currentTheme = theme;
} catch (err) {
console.error('保存主题失败', err);
}
}
async saveFontSize(size: number) {
try {
await PreferencesUtils.put('fontSize', size);
this.fontSize = size;
} catch (err) {
console.error('保存字体大小失败', err);
}
}
build() {
Column() {
// 主题选择
Row() {
Button('浅色主题')
.onClick(() => this.saveTheme('light'))
Button('深色主题')
.onClick(() => this.saveTheme('dark'))
}
// 字体大小设置
Row() {
Text('字体大小:')
Slider({ value: this.fontSize, min: 12, max: 32 })
.onChange((value: number) => this.saveFontSize(value))
Text(`${this.fontSize}px`)
}
}
.backgroundColor(this.currentTheme === 'dark' ? '#333' : '#FFF')
.fontColor(this.currentTheme === 'dark' ? '#FFF' : '#000')
}
}
六、最佳实践与注意事项
1. 性能优化
- 批量操作:尽量减少flush()调用次数,可以批量修改多个值后一次性flush
- 避免频繁读写:频繁的磁盘IO会影响性能,建议将频繁修改的数据缓存在内存中
- 合理分文件:根据功能模块将数据存储到不同的Preferences文件中
2. 数据安全
- 不存储敏感信息:Preferences不支持加密存储,不要存储密码、token等敏感数据
- 数据验证:读取数据时提供默认值,避免空指针异常
- 错误处理:使用try-catch包装所有Preferences操作
3. 内存管理
- 及时释放:页面销毁时取消数据变更订阅,避免内存泄漏
- 控制数据量:建议存储的数据不超过一万条,避免内存占用过大
4. 数据类型限制
- 键值类型:Key为string类型,长度不超过1024字节
- 值类型:支持number、string、boolean及其数组类型
- 字符串长度:string类型值长度不超过16MB
总结
Preferences是HarmonyOS中简单易用的轻量级数据持久化方案,非常适合存储用户设置和应用配置信息。通过本文的学习,你已经掌握了Preferences的基本使用方法、数据变更订阅机制以及工具类封装技巧。
行动建议:
- 在EntryAbility中初始化Preferences实例
- 使用工具类封装提高代码复用性
- 合理使用数据变更订阅机制
- 遵循最佳实践,避免性能问题和内存泄漏
- 不要存储敏感信息到Preferences中
通过合理使用Preferences,你可以轻松实现应用配置的持久化存储,提升用户体验。

浙公网安备 33010602011771号