前言

OpenHarmony 原生 Preferences 是轻量键值存储,适合保存配置、开关、用户状态、token、主题模式等少量数据。但原生 API 存在大量重复代码、实例频繁创建、无法统一加密、没有统一回调、容易丢数据等问题。

本文基于 API23 封装一套企业级 PrefUtil 全局存储工具,支持自动初始化、统一读写、异步安全写入、批量清除、适配深色模式、登录状态、用户配置,完美适配前文四层架构,全项目统一使用,杜绝碎片化存储代码。

一、工具能力亮点

  • 全局单例 Preferences,无需重复获取实例
  • 封装 String、Boolean、Number、Object 全类型读写
  • 异步安全写入,避免主线程卡顿
  • 支持批量清空、单独删除 key
  • 适配全局主题、登录态、缓存配置
  • 配合全局架构,项目统一持久化方案

二、PrefUtil 完整源码(har_base/utils/pref_util.ets)

typescript

运行

import preferences from '@ohos.data.preferences';
import common from '@ohos.app.ability.common';
import LogUtil from './log_util';

const PREF_NAME = "app_global_config";

class PrefUtil {
  private ctx: common.UIAbilityContext | null = null;
  private dataPreferences: preferences.Preferences | null = null;

  setContext(ctx: common.UIAbilityContext) {
    this.ctx = ctx;
  }

  // 初始化全局偏好存储
  async init(): Promise<boolean> {
    if (!this.ctx) {
      LogUtil.error("PrefUtil", "上下文未初始化");
      return false;
    }
    try {
      this.dataPreferences = await preferences.getPreferences(this.ctx, PREF_NAME);
      LogUtil.info("PrefUtil", "全局偏好存储初始化成功");
      return true;
    } catch (e) {
      LogUtil.error("PrefUtil", "偏好存储初始化失败", e);
      return false;
    }
  }

  // 保存字符串
  async putString(key: string, value: string) {
    if (!this.dataPreferences) await this.init();
    await this.dataPreferences!.put(key, value);
    await this.dataPreferences!.flush();
  }

  // 读取字符串
  getString(key: string, def: string = ""): string {
    if (!this.dataPreferences) return def;
    return this.dataPreferences!.getSync(key, def) as string;
  }

  // 保存布尔值
  async putBoolean(key: string, value: boolean) {
    if (!this.dataPreferences) await this.init();
    await this.dataPreferences!.put(key, value);
    await this.dataPreferences!.flush();
  }

  // 读取布尔值
  getBoolean(key: string, def: boolean = false): boolean {
    if (!this.dataPreferences) return def;
    return this.dataPreferences!.getSync(key, def) as boolean;
  }

  // 保存数字
  async putNumber(key: string, value: number) {
    if (!this.dataPreferences) await this.init();
    await this.dataPreferences!.put(key, value);
    await this.dataPreferences!.flush();
  }

  // 读取数字
  getNumber(key: string, def: number = 0): number {
    if (!this.dataPreferences) return def;
    return this.dataPreferences!.getSync(key, def) as number;
  }

  // 保存对象(JSON)
  async putObject<T>(key: string, value: T) {
    const jsonStr = JSON.stringify(value);
    await this.putString(key, jsonStr);
  }

  // 读取对象
  getObject<T>(key: string): T | null {
    const str = this.getString(key);
    if (!str) return null;
    try {
      return JSON.parse(str) as T;
    } catch {
      return null;
    }
  }

  // 删除单个 key
  async deleteKey(key: string) {
    if (!this.dataPreferences) await this.init();
    await this.dataPreferences!.delete(key);
    await this.dataPreferences!.flush();
  }

  // 清空全部存储
  async clearAll() {
    if (!this.dataPreferences) await this.init();
    await this.dataPreferences!.clear();
    await this.dataPreferences!.flush();
    LogUtil.info("PrefUtil", "本地偏好数据已全部清空");
  }
}

export default new PrefUtil();

三、全局初始化(EntryAbility)

在应用启动时统一初始化,保证全局可用:

typescript

运行

// EntryAbility onCreate
PrefUtil.setContext(context);
await PrefUtil.init();

四、标准业务调用示例

4.1 保存 / 读取用户 Token

typescript

运行

// 登录保存
await PrefUtil.putString("user_token", res.token);

// 读取
let token = PrefUtil.getString("user_token");

4.2 保存深色模式状态

typescript

运行

// 切换深色模式
await PrefUtil.putBoolean("dark_mode", true);

// 获取
let isDark = PrefUtil.getBoolean("dark_mode", false);

4.3 保存复杂对象(用户信息)

typescript

运行

interface UserInfo {
  name: string,
  avatar: string
}

// 存储
await PrefUtil.putObject<UserInfo>("user_info", {
  name: "鸿蒙开发者",
  avatar: "xxx.png"
});

// 读取
let user = PrefUtil.getObject<UserInfo>("user_info");

4.4 清空用户数据(退出登录)

typescript

运行

// 退出登录清空所有本地用户配置
await PrefUtil.deleteKey("user_token");
await PrefUtil.deleteKey("user_info");

五、工程统一规范(强制)

  • 所有轻量配置必须走 PrefUtil,禁止原生 preferences 散写页面
  • 主题、设置、开关、用户信息、token 全部统一托管
  • 页面销毁不需要关闭,Preferences 由全局单例管理
  • 大量结构化数据、列表数据禁止用 Pref,统一使用 RdbUtil
  • 所有写入操作异步执行,读取同步执行,保证 UI 流畅

六、常见问题解决

问题 1:读取数据为空

原因:未在 EntryAbility 初始化、key 名不一致、未 flush。 解决方案:全局初始化一次,工具内部已自动 flush。

问题 2:对象读取报错 JSON 解析失败

解决方案:工具内部捕获异常,失败自动返回 null,不会崩溃页面。

问题 3:多页面读写冲突

解决方案:全局单例实例,不存在多实例冲突。

七、总结

PrefUtil 是整套四层架构中轻量持久化唯一标准工具,替代原生零散写法,统一管理全局配置、用户状态、主题缓存,适配所有页面、HAR、HSP 分包,是鸿蒙项目规范化、商业化、毕设项目必备底层能力。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐