引言

你的App里是不是经常要存这些东西:主题暗色/亮色、字体大小、自动保存开关、上次登录时间……

数据量小、读写频繁、不值得开数据库——那就对了,这就是 HarmonyOS @ohos.data.preferences 的战场。

Preferences 是鸿蒙内置的轻量级键值对存储方案,属于 @kit.ArkData。一句话总结它的API设计:异步获取实例,同步操作数据。支持 9 种数据类型,数据自动持久化为沙箱内 XML 文件,卸载即清除,零权限。

本文带你从零上手 Preferences,并在文末构建一个完整的"首选项实验室"Demo。


一、核心API一览

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

获取实例是唯一的异步操作:

const ctx = getContext(this);
preferences.getPreferences(ctx, 'my_config').then((prefs) => {
  // 之后全是同步操作
  prefs.putSync('theme', 'dark');
  prefs.flushSync();
});

拿到实例后,你只需要记住这6个方法:

方法 说明
putSync(key, value) 写入键值对
getSync(key, defValue) 读取值(不存在返回默认值)
hasSync(key) 检查键是否存在
deleteSync(key) 删除指定键
flushSync() 强制写入磁盘
on/off('change', cb) 注册/移除变更监听

设计哲学:getPreferences 需要从磁盘加载XML文件,所以是异步的。但加载完成后所有操作都在内存中进行,所以设计为同步方法——既保证了UI不被阻塞,又让代码写起来简单直接。


二、ValueType:9种数据类型随便存

type ValueType = number | string | boolean | Array<number> | Array<string> |
                 Array<boolean> | Uint8Array | object | bigint;

看几个实际例子:

prefs.putSync('username', 'Alice');        // 字符串
prefs.putSync('fontSize', 16);              // 数字
prefs.putSync('autoSave', true);            // 布尔
prefs.putSync('userProfile', {              // 对象(自动序列化)
  name: 'Alice', age: 25, vip: true 
});
prefs.putSync('maxId', BigInt(999999));     // bigint
prefs.putSync('avatar', new Uint8Array(     // 二进制
  [0x89, 0x50, 0x4E, 0x47]
));

两个硬性限制要记住:

  • MAX_KEY_LENGTH = 80:键名最长80字符
  • MAX_VALUE_LENGTH = 8192:字符串值最长8192字符

超过限制就用 @ohos.file.fs 文件存储,别硬塞 Preferences。


三、flushSync:数据落盘的关键一步

putSync写入

内存中的键值数据

调用flushSync?

写入磁盘XML文件

仅存在内存中
崩溃即丢失

关键点:不调 flushSync(),数据只在内存里。App崩溃或被系统杀死,数据就丢了。

prefs.putSync('theme', 'dark');
prefs.putSync('fontSize', 14);
prefs.flushSync(); // 此时才真正写磁盘

文件存在沙箱里,路径是 /data/storage/el2/base/preferences/,直接用文本编辑器就能打开看:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<preferences>
  <string name="username">Alice</string>
  <int name="fontSize" value="16"/>
  <boolean name="autoSave" value="true"/>
</preferences>

可读、可手动修复、可调试——这是 Preferences 相比数据库的一大优势。


四、变更监听:on/off(‘change’)

// 注册监听
prefs.on('change', (data: { key: string }) => {
  console.log('键值已变更: ' + data.key);
});

// 移除监听
prefs.off('change');

最常用的两个场景:

  1. 跨页面配置同步:页面A改了主题,页面B通过 change 事件立即感知
  2. 调试审计:开发阶段追踪所有配置变更

注意:组件销毁时一定要 off('change'),否则内存泄漏。


五、实战:首选项存储实验室

下面构建一个完整Demo,在页面上完成键值对的写入、读取、删除和实时监听。

5.1 状态模型设计

@State prefsReady: boolean = false;    // Preferences是否已加载
@State writeKey: string = 'username';
@State writeValue: string = 'Alice';
@State writeType: string = 'string';   // string/number/boolean
@State readKey: string = '';
@State readResult: string = '--';
@State kvList: KvEntry[] = [];         // 已存储的键值列表
@State listenOn: boolean = false;
@State logs: LogEntry[] = [];
private prefs: preferences.Preferences | null = null;

5.2 异步加载 + 同步操作

aboutToAppear(): void {
  const ctx = getContext(this);
  preferences.getPreferences(ctx, 'lab_prefs').then((p) => {
    this.prefs = p;
    this.prefsReady = true;
    this.loadAllKeys();
  }).catch((e) => {
    console.error('加载失败: ' + e.message);
  });
}

5.3 写入带类型选择

private saveValue(): void {
  if (!this.prefs) return;
  let value: preferences.ValueType;
  switch (this.writeType) {
    case 'number':
      value = parseFloat(this.writeValue);
      if (isNaN(value)) return;
      break;
    case 'boolean':
      value = this.writeValue.toLowerCase() === 'true';
      break;
    default:
      value = this.writeValue;
  }
  this.prefs.putSync(this.writeKey.trim(), value);
  this.prefs.flushSync();
  this.loadAllKeys();
}

5.4 扫描已存储键值

private loadAllKeys(): void {
  if (!this.prefs) return;
  this.kvList = [];
  const testKeys = ['username', 'theme', 'fontSize', 'autoSave', 'lastLogin'];
  for (const key of testKeys) {
    const val = this.prefs.getSync(key, '');
    if (val !== '' && val !== undefined && val !== null) {
      this.kvList.push({ key, value: val.toString(), vtype: typeof val });
    }
  }
}

5.5 变更监听开关

private toggleListener(): void {
  if (!this.prefs) return;
  if (this.listenOn) {
    this.prefs.off('change');
    this.listenOn = false;
  } else {
    this.prefs.on('change', () => {
      this.loadAllKeys();
    });
    this.listenOn = true;
  }
}

5.6 组件销毁清理

aboutToDisappear(): void {
  if (this.listenOn && this.prefs) {
    this.prefs.off('change');
  }
}

六、最佳实践清单

✅ 什么时候用 Preferences

  • 用户配置:主题、字体大小、开关设置
  • 应用状态:首次启动标记、上次选择Tab
  • 轻量缓存:最近搜索关键词、布局偏好

❌ 什么时候别用

  • 数据量 > 100 个键值对 → 用 @ohos.data.relationalStore
  • 单值 > 8KB → 用 @ohos.file.fs
  • 复杂查询 → 用数据库
  • 密码/Token → 用 @ohos.security.huks

⚠️ 异常处理

所有同步操作都要 try/catch 保护:

try {
  prefs.putSync(key, value);
  prefs.flushSync();
} catch (e) {
  console.error('写入失败: ' + (e as Error).message);
}

总结

getPreferences异步获取实例

putSync/getSync/deleteSync

flushSync确保落盘

on/off管理变更监听

aboutToDisappear中off清理

所有操作try/catch保护

@ohos.data.preferences 是鸿蒙数据存储体系中的"轻骑兵"——与 @ohos.data.relationalStore(关系数据库)、@ohos.data.distributedKVStore(分布式KV)、@ohos.file.fs(文件存储)形成完整的数据能力栈。它是应用设置和用户偏好的第一选择:简单、可靠、零权限、开箱即用。

Logo

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

更多推荐