第20篇:鸿蒙应用数据持久化——Preferences 首选项详解

img

一、引言

数据持久化是应用开发的基础需求。在鸿蒙中,Preferences 首选项 API 提供了轻量级的数据持久化能力,适合存储键值对形式的配置数据。DriverLicenseExam 项目使用 Preferences 来存储深色模式、服务卡片 ID 等用户偏好数据。本文将深入解析其实现。

二、PreferencesUtil 封装

2.1 单例封装

// commons/commonLib/src/main/ets/utils/PreferencesUtil.ets
export class PreferencesUtil {
  private static preferencesUtil: PreferencesUtil;
  private static readonly MY_STORE: string = 'myStore';

  public static getInstance(): PreferencesUtil {
    if (!PreferencesUtil.preferencesUtil) {
      PreferencesUtil.preferencesUtil = new PreferencesUtil();
    }
    return PreferencesUtil.preferencesUtil;
  }
}

2.2 核心方法

// 获取 Preferences 实例
getPreferences(context: Context): preferences.Preferences {
  try {
    preferences.removePreferencesFromCacheSync(context, MY_STORE);
  } catch (e) {}
  return preferences.getPreferencesSync(context, { name: MY_STORE });
}

// 写入数据
preferencesPut(preferences: preferences.Preferences, key: string, value: preferences.ValueType): void {
  preferences.putSync(key, value);
  this.preferencesFlush(preferences);
}

// 读取数据
getPreferencesValue(preferences: preferences.Preferences, key: string): preferences.ValueType {
  if (preferences === null) {
    Logger.error(TAG, 'preferences is null');
    return '';
  }
  return preferences.getSync(key, '');
}

// 检查 key 是否存在
hasPreferencesKey(preferences: preferences.Preferences, key: string): boolean {
  if (preferences === null) return false;
  return preferences.hasSync(key);
}

// 刷新(同步到磁盘)
preferencesFlush(preferences: preferences.Preferences) {
  try {
    preferences.flush((err) => {
      if (err) {
        Logger.error(TAG, 'Failed to flush. Code: ${err.code}, message: ${err.message}');
      }
    });
  } catch (e) {
    Logger.error(TAG, 'Failed to call preferences.flush: ${JSON.stringify(e)}');
  }
}

三、实际应用场景

3.1 深色模式持久化

// EntryAbility.ets 中恢复深色模式
private setLightOrDarkMode(context: Context) {
  const preferencesUtil = PreferencesUtil.getInstance();
  const preference = preferencesUtil.getPreferences(context);
  const value = preferencesUtil.getPreferencesValue(preference, 'lightDarkMode') || 0;
  AppStorage.setOrCreate('lightDarkMode', value);

  if (value === 0) {
    context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
  } else if (value === 1) {
    context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
  } else if (value === 2) {
    context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
  }
}

3.2 服务卡片数据持久化

// MainEntry.ets 中更新卡片数据
updateForm(index: number) {
  const preferencesUtil = PreferencesUtil.getInstance();
  const preference = preferencesUtil.getPreferences(this.getUIContext().getHostContext() as Context);
  
  preferencesUtil.preferencesPut(preference, 'tabIndex', index);
  preferencesUtil.preferencesPut(preference, 'didCount', this.didCount);
  preferencesUtil.preferencesPut(preference, 'totalCount', this.totalCount);
  
  // 更新服务卡片
  const formInfo = formBindingData.createFormBindingData(newData);
  formIds.forEach((id: string) => {
    formProvider.updateForm(id, formInfo);
  });
}

3.3 表单 ID 管理

// 获取所有表单 ID
getFormIds(preferences: preferences.Preferences): Array<string> {
  if (preferences === null) return [];
  return preferences.getSync('formIdList', ['']) as Array<string>;
}

// 添加表单 ID
addFormId(preferences: preferences.Preferences, formId: string): void {
  if (preferences.hasSync('formIdList')) {
    let formIds = this.getFormIds(preferences);
    if (formIds.indexOf(formId) === -1) {
      formIds.push(formId);
      this.preferencesPut(preferences, 'formIdList', formIds);
    }
  } else {
    this.preferencesPut(preferences, 'formIdList', [formId]);
  }
}

// 移除表单 ID
removeFormId(context: Context, formId: string) {
  let preferences = this.getPreferences(context);
  if (preferences.hasSync('formIdList')) {
    let formIds = this.getFormIds(preferences);
    let index = formIds.indexOf(formId);
    if (index !== -1) {
      formIds.splice(index, 1);
      this.preferencesPut(preferences, 'formIdList', formIds);
    }
  }
}

四、Preferences 最佳实践

4.1 使用原则

// 1. 缓存清除:每次获取前清除缓存,确保数据最新
preferences.removePreferencesFromCacheSync(context, MY_STORE);

// 2. 写入后立即刷新
preferences.putSync(key, value);
this.preferencesFlush(preferences);  // 立即同步到磁盘

// 3. 异常处理:所有操作都需 try-catch
try {
  preferences.putSync(key, value);
} catch (e) {
  Logger.error(TAG, 'Failed to put preferences: ${JSON.stringify(e)}');
}

4.2 适用场景

  • 用户偏好设置(深色模式、字体大小等)
  • 应用配置数据
  • 缓存少量结构化数据
  • 服务卡片相关数据

五、总结

Preferences 首选项是鸿蒙应用中最常用的轻量级数据持久化方案。通过 PreferencesUtil 的封装,项目实现了统一的数据读写接口,支持深色模式、服务卡片等场景的数据持久化。


关键源码文件:

  • commons/commonLib/src/main/ets/utils/PreferencesUtil.ets — 首选项封装
  • products/entry/src/main/ets/entryability/EntryAbility.ets — 深色模式持久化
  • products/entry/src/main/ets/pages/MainEntry.ets — 卡片数据持久化
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐