Harmony之路:数据持久化——Preferences本地存储方案

Harmony之路:数据持久化——Preferences本地存储方案

一、引入:为什么需要数据持久化?

在移动应用开发中,我们经常需要保存用户的配置信息、登录状态、应用数据等,这些数据需要在应用关闭后仍然保留。HarmonyOS提供了Preferences作为轻量级数据存储方案,它采用键值对的方式存储数据,支持多种数据类型,适合存储小量、简单的数据。掌握Preferences的使用,是构建完整应用的必要技能。

二、讲解:Preferences的核心用法

1. Preferences基础操作

Preferences提供了类似键值对的存储机制,支持字符串、数字、布尔值、数组等多种数据类型的存储和读取。

基础数据操作示例:

import preferences from '@ohos.data.preferences';

// 获取Preferences实例
const context = getContext(this) as common.UIAbilityContext;
const preferences = await preferences.getPreferences(context, 'myAppData');

// 设置数据
await preferences.put('username', '张三');
await preferences.put('userAge', 25);
await preferences.put('isLogin', false);
await preferences.put('lastLoginTime', Date.now());

// 获取数据
const username = await preferences.get('username', '');
const userAge = await preferences.get('userAge', 0);
const isLogin = await preferences.get('isLogin', false);
const lastLoginTime = await preferences.get('lastLoginTime', 0);

console.log('用户信息:', username, userAge, isLogin, new Date(lastLoginTime));

// 检查是否存在
const hasUsername = await preferences.has('username');
console.log('是否存在username:', hasUsername);

// 删除数据
await preferences.delete('username');

// 清空所有数据
await preferences.clear();

2. 数据同步与异步操作

Preferences提供了同步和异步两种操作方式,推荐使用异步操作避免阻塞UI线程。

同步操作示例:

// 同步获取Preferences实例
const preferences = preferences.getPreferencesSync(context, 'myAppData');

// 同步设置数据
preferences.putSync('key', 'value');

// 同步获取数据
const value = preferences.getSync('key', 'default');

// 同步删除数据
preferences.deleteSync('key');

// 同步清空
preferences.clearSync();

异步操作示例(推荐):

// 异步获取Preferences实例
const preferences = await preferences.getPreferences(context, 'myAppData');

// 异步设置数据
await preferences.put('key', 'value');

// 异步获取数据
const value = await preferences.get('key', 'default');

// 异步删除数据
await preferences.delete('key');

// 异步清空
await preferences.clear();

3. 存储复杂数据类型

Preferences支持存储对象和数组等复杂数据类型,但需要先转换为JSON字符串。

对象存储示例:

class UserInfo {
  name: string;
  age: number;
  email: string;

  constructor(name: string, age: number, email: string) {
    this.name = name;
    this.age = age;
    this.email = email;
  }
}

// 存储对象
const user = new UserInfo('张三', 25, 'zhangsan@example.com');
await preferences.put('userInfo', JSON.stringify(user));

// 读取对象
const userStr = await preferences.get('userInfo', '');
if (userStr) {
  const userInfo: UserInfo = JSON.parse(userStr);
  console.log('用户信息:', userInfo.name, userInfo.age, userInfo.email);
}

数组存储示例:

// 存储数组
const todoList = ['学习ArkTS', '掌握Preferences', '完成项目'];
await preferences.put('todoList', JSON.stringify(todoList));

// 读取数组
const todoStr = await preferences.get('todoList', '');
if (todoStr) {
  const todos: string[] = JSON.parse(todoStr);
  console.log('待办事项:', todos);
}

4. 数据变化监听

Preferences支持监听数据变化,当指定键的值发生变化时触发回调。

数据变化监听示例:

// 添加数据变化监听
const dataChangeListener: preferences.DataChangeListener = {
  onDataChange: (key: string) => {
    console.log(`数据发生变化: ${key}`);
    // 重新读取数据
    this.loadData();
  }
};

// 注册监听
preferences.on('dataChange', dataChangeListener);

// 取消监听
preferences.off('dataChange', dataChangeListener);

5. 实际应用场景

场景1:用户登录状态管理

class UserService {
  private static preferences: preferences.Preferences;

  // 初始化Preferences
  static async init(context: common.UIAbilityContext) {
    this.preferences = await preferences.getPreferences(context, 'userData');
  }

  // 保存用户信息
  static async saveUserInfo(user: UserInfo) {
    await this.preferences.put('userInfo', JSON.stringify(user));
    await this.preferences.put('isLogin', true);
    await this.preferences.put('lastLoginTime', Date.now());
  }

  // 获取用户信息
  static async getUserInfo(): Promise<UserInfo | null> {
    const userStr = await this.preferences.get('userInfo', '');
    return userStr ? JSON.parse(userStr) : null;
  }

  // 检查登录状态
  static async isLogin(): Promise<boolean> {
    return await this.preferences.get('isLogin', false);
  }

  // 退出登录
  static async logout() {
    await this.preferences.delete('userInfo');
    await this.preferences.put('isLogin', false);
  }
}

// 在应用入口初始化
@Entry
@Component
struct MainPage {
  async aboutToAppear() {
    const context = getContext(this) as common.UIAbilityContext;
    await UserService.init(context);
  }

  build() {
    // 页面内容
  }
}

场景2:应用配置管理

class AppConfig {
  private static preferences: preferences.Preferences;

  // 配置项键名
  private static readonly KEYS = {
    THEME: 'theme',
    LANGUAGE: 'language',
    NOTIFICATION: 'notification',
    SOUND: 'sound'
  };

  static async init(context: common.UIAbilityContext) {
    this.preferences = await preferences.getPreferences(context, 'appConfig');
  }

  // 保存主题配置
  static async setTheme(theme: string) {
    await this.preferences.put(this.KEYS.THEME, theme);
  }

  // 获取主题配置
  static async getTheme(): Promise<string> {
    return await this.preferences.get(this.KEYS.THEME, 'light');
  }

  // 保存语言配置
  static async setLanguage(language: string) {
    await this.preferences.put(this.KEYS.LANGUAGE, language);
  }

  // 获取语言配置
  static async getLanguage(): Promise<string> {
    return await this.preferences.get(this.KEYS.LANGUAGE, 'zh-CN');
  }

  // 保存通知设置
  static async setNotification(enabled: boolean) {
    await this.preferences.put(this.KEYS.NOTIFICATION, enabled);
  }

  // 获取通知设置
  static async getNotification(): Promise<boolean> {
    return await this.preferences.get(this.KEYS.NOTIFICATION, true);
  }

  // 保存声音设置
  static async setSound(enabled: boolean) {
    await this.preferences.put(this.KEYS.SOUND, enabled);
  }

  // 获取声音设置
  static async getSound(): Promise<boolean> {
    return await this.preferences.get(this.KEYS.SOUND, true);
  }
}

场景3:历史记录管理

class HistoryManager {
  private static preferences: preferences.Preferences;
  private static readonly MAX_HISTORY = 10;

  static async init(context: common.UIAbilityContext) {
    this.preferences = await preferences.getPreferences(context, 'searchHistory');
  }

  // 添加搜索历史
  static async addSearchHistory(keyword: string) {
    let history: string[] = await this.getSearchHistory();
    
    // 移除重复项
    history = history.filter(item => item !== keyword);
    
    // 添加到开头
    history.unshift(keyword);
    
    // 限制数量
    if (history.length > this.MAX_HISTORY) {
      history = history.slice(0, this.MAX_HISTORY);
    }
    
    await this.preferences.put('searchHistory', JSON.stringify(history));
  }

  // 获取搜索历史
  static async getSearchHistory(): Promise<string[]> {
    const historyStr = await this.preferences.get('searchHistory', '');
    return historyStr ? JSON.parse(historyStr) : [];
  }

  // 清空搜索历史
  static async clearSearchHistory() {
    await this.preferences.delete('searchHistory');
  }
}

6. 性能优化与最佳实践

1. 合理使用Preferences

  • 适合存储小量、简单的配置数据
  • 不适合存储大量数据或频繁读写的数据
  • 对于大量数据,应该使用关系型数据库(如RDB)

2. 数据加密

对于敏感数据,应该进行加密存储:

import cryptoFramework from '@ohos.security.cryptoFramework';

// 加密数据
async function encryptData(data: string, key: string): Promise<string> {
  // 使用cryptoFramework进行加密
  // 具体实现略
  return encryptedData;
}

// 解密数据
async function decryptData(encryptedData: string, key: string): Promise<string> {
  // 使用cryptoFramework进行解密
  // 具体实现略
  return decryptedData;
}

// 存储加密数据
const sensitiveData = '敏感信息';
const encrypted = await encryptData(sensitiveData, 'mySecretKey');
await preferences.put('sensitiveData', encrypted);

// 读取解密数据
const encryptedData = await preferences.get('sensitiveData', '');
if (encryptedData) {
  const decrypted = await decryptData(encryptedData, 'mySecretKey');
  console.log('解密数据:', decrypted);
}

3. 数据备份与恢复

实现数据备份功能:

class DataBackup {
  private static preferences: preferences.Preferences;

  static async init(context: common.UIAbilityContext) {
    this.preferences = await preferences.getPreferences(context, 'appData');
  }

  // 导出数据
  static async exportData(): Promise<string> {
    const allData = await this.preferences.getAll();
    return JSON.stringify(allData);
  }

  // 导入数据
  static async importData(data: string) {
    const dataObj = JSON.parse(data);
    for (const [key, value] of Object.entries(dataObj)) {
      await this.preferences.put(key, value);
    }
  }

  // 重置数据
  static async resetData() {
    await this.preferences.clear();
  }
}

4. 错误处理

为Preferences操作添加错误处理:

class SafePreferences {
  private preferences: preferences.Preferences;

  constructor(context: common.UIAbilityContext, name: string) {
    this.preferences = preferences.getPreferencesSync(context, name);
  }

  async put(key: string, value: preferences.ValueType): Promise<boolean> {
    try {
      await this.preferences.put(key, value);
      return true;
    } catch (error) {
      console.error('保存数据失败:', error);
      return false;
    }
  }

  async get(key: string, defaultValue: preferences.ValueType): Promise<preferences.ValueType> {
    try {
      return await this.preferences.get(key, defaultValue);
    } catch (error) {
      console.error('读取数据失败:', error);
      return defaultValue;
    }
  }

  async delete(key: string): Promise<boolean> {
    try {
      await this.preferences.delete(key);
      return true;
    } catch (error) {
      console.error('删除数据失败:', error);
      return false;
    }
  }
}

三、总结:数据持久化的核心要点

✅ 核心知识点回顾

  1. Preferences是轻量级存储:采用键值对方式存储数据,适合小量、简单的配置数据
  2. 支持多种数据类型:字符串、数字、布尔值、数组、对象(需JSON序列化)
  3. 同步与异步操作:提供同步和异步两种操作方式,推荐使用异步操作
  4. 数据变化监听:可以监听指定键的数据变化
  5. 数据加密:敏感数据应该进行加密存储

⚠️ 常见问题与解决方案

  1. 数据丢失:确保在应用启动时初始化Preferences,避免在异步操作完成前读取数据
  2. 类型错误:读取数据时指定正确的默认值类型,避免类型转换错误
  3. 性能问题:避免频繁读写大量数据,对于大量数据应该使用关系型数据库
  4. 数据安全:敏感数据必须进行加密存储,避免明文存储

🎯 最佳实践建议

  1. 合理使用:Preferences适合存储配置信息、用户设置等小量数据
  2. 封装管理:将Preferences操作封装到服务类中,提高代码可维护性
  3. 错误处理:为所有Preferences操作添加错误处理,避免应用崩溃
  4. 数据备份:实现数据备份和恢复功能,提高用户体验

下一步预告:在第十一篇中,我们将学习网络请求,掌握使用HTTP模块进行网络数据交互的方法,实现应用与服务器的数据通信。

posted @ 2025-12-23 23:03  蓝莓Reimay  阅读(2)  评论(0)    收藏  举报