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,你可以輕鬆實現應用配置的持久化存儲,提升用户體驗。