HarmonyOS数据持久化最佳实践——Preferences首选项存储详解

技术栈:HarmonyOS 5.0 + ArkTS + @ohos.data.preferences

适用场景:用户设置、历史记录、应用状态保存


前言

在应用开发中,数据持久化是必不可少的功能。HarmonyOS提供了@ohos.data.preferences模块用于轻量级数据存储。本文将介绍如何封装一个通用的首选项工具类。

一、Preferences vs 关系型数据库

特性 Preferences 关系型数据库
数据量 小(KB级) 大(MB级)
数据结构 键值对 表结构
查询能力 简单 复杂SQL
适用场景 用户设置 业务数据

二、工具类封装

2.1 基础工具类

typescript 复制代码
import dataPreferences from '@ohos.data.preferences';
import common from '@ohos.app.ability.common';

export class PreferencesUtil {
  private static readonly PREFERENCES_NAME = 'app_preferences';
  private static preferences: dataPreferences.Preferences | null = null;

  /**
   * 初始化(必须在EntryAbility.onCreate中调用)
   */
  static async init(context: common.UIAbilityContext): Promise<void> {
    try {
      PreferencesUtil.preferences = await dataPreferences.getPreferences(
        context,
        PreferencesUtil.PREFERENCES_NAME
      );
      console.info('PreferencesUtil: 初始化成功');
    } catch (err) {
      console.error('PreferencesUtil: 初始化失败', err);
    }
  }

  static async putString(key: string, value: string): Promise<void> {
    if (!PreferencesUtil.preferences) return;
    await PreferencesUtil.preferences.put(key, value);
    await PreferencesUtil.preferences.flush();
  }

  static async getString(key: string, defaultValue: string = ''): Promise<string> {
    if (!PreferencesUtil.preferences) return defaultValue;
    return await PreferencesUtil.preferences.get(key, defaultValue) as string;
  }

  static async putNumber(key: string, value: number): Promise<void> {
    if (!PreferencesUtil.preferences) return;
    await PreferencesUtil.preferences.put(key, value);
    await PreferencesUtil.preferences.flush();
  }

  static async getNumber(key: string, defaultValue: number = 0): Promise<number> {
    if (!PreferencesUtil.preferences) return defaultValue;
    return await PreferencesUtil.preferences.get(key, defaultValue) as number;
  }

  static async putBoolean(key: string, value: boolean): Promise<void> {
    if (!PreferencesUtil.preferences) return;
    await PreferencesUtil.preferences.put(key, value);
    await PreferencesUtil.preferences.flush();
  }

  static async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {
    if (!PreferencesUtil.preferences) return defaultValue;
    return await PreferencesUtil.preferences.get(key, defaultValue) as boolean;
  }

  static async delete(key: string): Promise<void> {
    if (!PreferencesUtil.preferences) return;
    await PreferencesUtil.preferences.delete(key);
    await PreferencesUtil.preferences.flush();
  }
}

2.2 复杂对象存储

typescript 复制代码
export interface HearingTestResult {
  id: string;
  timestamp: number;
  maxFrequency: number;
  hearingAge: number;
  level: string;
}

export class TestHistoryManager {
  private static readonly KEY = 'hearing_test_history';

  static async saveResult(result: HearingTestResult): Promise<void> {
    const history = await TestHistoryManager.getHistory();
    history.push(result);
    // 只保留最近20条
    const trimmed = history.slice(-20);
    await PreferencesUtil.putString(this.KEY, JSON.stringify(trimmed));
  }

  static async getHistory(): Promise<HearingTestResult[]> {
    const str = await PreferencesUtil.getString(this.KEY, '[]');
    try {
      return JSON.parse(str) as HearingTestResult[];
    } catch {
      return [];
    }
  }
}

2.3 键名常量管理

typescript 复制代码
export const PreferencesKeys = {
  VIBRATION_ENABLED: 'vibration_enabled',
  VOLUME_LEVEL: 'volume_level',
  THEME_MODE: 'theme_mode',
  USE_COUNT: 'use_count',
  TOTAL_DURATION: 'total_duration',
  ONBOARDING_COMPLETED: 'onboarding_completed',
};

三、在EntryAbility中初始化

typescript 复制代码
import { UIAbility } from '@ohos.app.ability.UIAbility';
import { PreferencesUtil } from 'common';

export default class EntryAbility extends UIAbility {
  async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
    await PreferencesUtil.init(this.context);
  }
}

四、使用示例

typescript 复制代码
// 保存用户设置
await PreferencesUtil.putBoolean(PreferencesKeys.VIBRATION_ENABLED, true);
await PreferencesUtil.putNumber(PreferencesKeys.VOLUME_LEVEL, 80);

// 读取用户设置
const vibrationEnabled = await PreferencesUtil.getBoolean(PreferencesKeys.VIBRATION_ENABLED, true);
const volumeLevel = await PreferencesUtil.getNumber(PreferencesKeys.VOLUME_LEVEL, 80);

// 保存复杂对象
const result: HearingTestResult = {
  id: Date.now().toString(),
  timestamp: Date.now(),
  maxFrequency: 16000,
  hearingAge: 25,
  level: '正常'
};
await TestHistoryManager.saveResult(result);

五、避坑指南

  1. 初始化时机 :必须在EntryAbility.onCreate中初始化
  2. flush调用 :每次put后都要调用flush()
  3. JSON序列化 :复杂对象需要JSON.stringify/JSON.parse
  4. 数据量限制:Preferences适合小数据,大数据用关系型数据库
  5. 异步处理 :所有操作都是异步的,注意使用await

总结

本文封装了一个通用的Preferences工具类,支持基础类型和复杂对象的存储。在实际项目中,这个工具类被用于保存用户设置、测试历史、使用统计等数据。

相关推荐
IntMainJhy2 小时前
「Flutter三方库sqflite的鸿蒙化适配与实战指南:从入门到踩坑的本地数据库开发全记录」
数据库·flutter·华为·信息可视化·数据库开发·harmonyos
前端技术4 小时前
HarmonyOS开发:鸿蒙应用开发发展史
华为·harmonyos
Hello__77775 小时前
开源鸿蒙 Flutter 实战|自定义头像组件全流程实现
flutter·华为·harmonyos
IntMainJhy7 小时前
【flutter for open harmony】第三方库Flutter成就解锁彩纸动画的鸿蒙化适配与实战指南
harmonyos
Lanren的编程日记7 小时前
任务77:Flutter 鸿蒙应用视频录制功能实战:视频录制+录制控制+视频编辑,打造完整视频处理能力
flutter·音视频·harmonyos
Hello__77777 小时前
开源鸿蒙 Flutter 实战|进度条组件全流程实现
flutter·开源·harmonyos
音视频牛哥7 小时前
SmartMediaKit 鸿蒙NEXT 产品生态之RTMP推流、轻量级RTSP服务与推送端录像能力详解
音视频·harmonyos·鸿蒙rtmp播放器·鸿蒙rtsp播放器·鸿蒙rtmp推流·鸿蒙next下rtmp同屏·鸿蒙rtsp服务器
IntMainJhy7 小时前
【flutter for open harmony】第三方库 Flutter分享卡片的鸿蒙化适配与实战指南
flutter·华为·harmonyos
Lanren的编程日记8 小时前
任务76:Flutter 鸿蒙应用音频录制功能实战:音频录制+录音管理+录音编辑,打造完整音频处理能力
flutter·华为·音视频·harmonyos
前端不太难8 小时前
鸿蒙游戏的“帧”到底是什么?
游戏·状态模式·harmonyos