在 HarmonyOS 应用开发中,轻量级数据持久化是高频需求 —— 比如存储用户登录状态、应用启动配置、界面主题偏好、简单的用户设置等。鸿蒙官方提供的Preferences(用户首选项)正是为这类场景设计的键值型存储方案,无需复杂的数据库配置,支持快速的增删改查,是轻量级数据持久化的首选。本文将从核心概念、使用限制、实战代码到避坑指南,全面讲解Preferences的使用方法。

一、Preferences 核心概念与适用场景

1. 什么是 Preferences?

Preferences(用户首选项)是鸿蒙 ArkTS 提供的Key-Value 键值型数据处理能力,专为应用轻量级数据持久化设计:

  • 数据以键值对形式存储,键(Key)为字符串类型,值(Value)支持数字、字符串、布尔型及这 3 种类型的数组;
  • 数据持久化存储在应用私有目录,无需手动管理文件路径,系统自动维护;
  • 操作 API 简洁(同步 / 异步),开发成本低,读写性能优于关系型数据库。

2. 典型适用场景

  • 存储应用基础配置:如启动模式(auto/manual)、是否开启推送、界面亮度值;
  • 存储用户简单状态:如登录状态标记、最近浏览的试题 ID、默认字体大小;
  • 存储临时轻量数据:如表单填写的临时缓存、弹窗是否已展示的标记。

注意:Preferences不适合存储大量 / 复杂数据(如完整的试题列表、用户日志),这类场景建议使用 RelationalStore(关系型数据库)或分布式数据库。

二、Preferences 使用限制(必看)

使用Preferences前必须遵守以下限制,否则会导致数据存储失败或应用异常:

限制类型 具体要求
Key 键限制 ① 类型为 string,非空;② 长度不超过 1024 个字节(约 1KB)
Value 值限制 ① 支持类型:数字、字符串、布尔型及对应数组;② 字符串类型需用 UTF-8 编码;③ 非空字符串长度不超过 16MB(1610241024 字节)
数据量限制 建议存储不超过 1 万条数据,否则会占用大量内存,导致应用卡顿 / 崩溃

三、实战:Preferences 完整增删改查(附代码解析)

下面基于你提供的核心代码,实现一个完整的Preferences操作示例,包含 “创建仓库、新增、读取、修改、删除、删库” 全流程。

第一步:前置准备(导入依赖)

首先在页面文件中导入Preferences和弹窗提示相关 API:

typescript

运行

import { preferences } from '@kit.ArkData'; // 核心:用户首选项API
import { promptAction, getContext } from '@kit.ArkUI'; // 弹窗提示+上下文获取

第二步:完整代码实现

typescript

运行

@Entry
@Component
struct Demo05Preferences {
  // 声明Preferences实例,初始为null
  store: preferences.Preferences | null = null;

  // 页面即将显示时初始化Preferences仓库(推荐在aboutToAppear中创建)
  aboutToAppear(): void {
    // 1. 创建/获取Preferences仓库(同步方式)
    // 参数1:组件上下文;参数2:配置项(name为仓库名称,唯一标识)
    this.store = preferences.getPreferencesSync(getContext(this), {
      name: 'test-store' // 仓库名称,自定义(建议语义化命名)
    });
  }

  build() {
    Column({ space: 10 }) {
      Text('Preferences 首选项操作演示')
        .fontSize(20)
        .fontWeight(600);

      // 按钮1:新增数据(Key: myName, Value: 张飞)
      Button('增加')
        .onClick(() => {
          // 判空:避免store未初始化导致报错
          if (!this.store) return;
          // 2. 新增/覆盖数据(同步方式)
          this.store.putSync('myName', '张飞');
          // 3. 刷盘:将内存数据持久化到本地(关键!)
          this.store.flush();
          promptAction.showToast({ message: '新增成功' });
        });

      // 按钮2:读取数据
      Button('读取')
        .onClick(() => {
          if (!this.store) return;
          // 4. 读取数据(同步方式)
          // 参数1:要读取的Key;参数2:默认值(Key不存在时返回)
          const value = this.store.getSync('myName', '');
          // 打印+弹窗展示结果
          console.log('读取到的值:', value?.toString());
          promptAction.showToast({ message: `读取结果:${value || '无数据'}` });
        });

      // 按钮3:修改数据(覆盖已有Key的值)
      Button('修改')
        .onClick(() => {
          if (!this.store) return;
          // 5. 修改数据(putSync会覆盖已有Key的值)
          this.store.putSync('myName', '貂蝉');
          this.store.flush(); // 必须刷盘才能持久化
          promptAction.showToast({ message: '修改成功' });
        });

      // 按钮4:删除指定Key的数据
      Button('删除')
        .onClick(() => {
          if (!this.store) return;
          // 6. 删除指定Key
          this.store.deleteSync('myName');
          this.store.flush(); // 刷盘确认删除
          promptAction.showToast({ message: '删除成功' });
        });

      // 按钮5:删除整个Preferences仓库
      Button('删库')
        .backgroundColor('#ff4444')
        .fontColor('#ffffff')
        .onClick(() => {
          try {
            // 7. 删除整个仓库(谨慎使用!)
            preferences.deletePreferences(getContext(this), {
              name: 'test-store'
            });
            this.store = null; // 清空实例,避免后续操作报错
            promptAction.showToast({ message: '仓库删除成功' });
          } catch (e) {
            console.error('删库失败:', e);
            promptAction.showToast({ message: '删库失败' });
          }
        });
    }
    .padding({ top: 40 })
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center);
  }
}

核心代码解析

1. 仓库初始化(创建 / 获取)

typescript

运行

this.store = preferences.getPreferencesSync(getContext(this), { name: 'test-store' });
  • getPreferencesSync:同步获取 Preferences 实例,若指定名称的仓库不存在则自动创建;
  • getContext(this):传递当前组件的上下文,是操作 Preferences 的必要参数(不能传字符串 'this',这是常见错误);
  • 仓库名称(name):唯一标识一个 Preferences 仓库,建议按业务模块命名(如 'user_setting'、'app_config')。
2. 新增 / 修改数据

typescript

运行

this.store.putSync('myName', '张飞');
this.store.flush();
  • putSync(key, value):新增或修改数据(Key 存在则覆盖,不存在则新增);
  • flush()核心! putSync仅将数据写入内存,需调用flush()才能将内存数据持久化到本地文件,否则应用重启后数据丢失。
3. 读取数据

typescript

运行

const value = this.store.getSync('myName', '');
  • getSync(key, defaultValue):读取指定 Key 的值,第二个参数为默认值(Key 不存在 / 读取失败时返回);
  • 返回值类型与存储的 Value 类型一致,建议用toString()统一处理(避免类型异常)。
4. 删除指定 Key

typescript

运行

this.store.deleteSync('myName');
this.store.flush();
  • deleteSync(key):删除指定 Key 的键值对,同样需要flush()刷盘确认。
5. 删除整个仓库

typescript

运行

preferences.deletePreferences(getContext(this), { name: 'test-store' });
  • deletePreferences:删除整个 Preferences 仓库(所有键值对都会被删除),需谨慎使用;
  • 删库后建议将store实例置为null,避免后续操作已删除的仓库导致报错。

四、关键避坑指南

1. 忘记调用 flush (),数据丢失

这是最常见的错误!putSync/deleteSync仅修改内存数据,必须调用 flush () 才能持久化。若未调用,应用重启后数据会恢复到上次 flush 的状态。

2. 上下文传递错误

错误写法:

typescript

运行

preferences.deletePreferences(getContext('this'), { name: 'test-store' });

正确写法:

typescript

运行

preferences.deletePreferences(getContext(this), { name: 'test-store' });

getContext的参数是组件实例this,而非字符串 'this',否则会导致上下文无效,操作失败。

3. Key/Value 超出长度限制

  • Key 长度超过 1024 字节:会直接抛出异常,建议 Key 简洁(如 'use_push' 而非 'user_setting_notification_push_status');
  • 字符串 Value 超过 16MB:会导致存储失败,这类大文本建议用文件存储(fileIo)。

4. 同步 API 阻塞主线程

示例中使用的getPreferencesSync/putSync等是同步 API,若操作大量数据(虽不建议),会阻塞 UI 主线程,导致页面卡顿。推荐使用异步 API

typescript

运行

// 异步创建仓库示例
async initStore() {
  try {
    this.store = await preferences.getPreferences(getContext(this), { name: 'test-store' });
  } catch (e) {
    console.error('初始化仓库失败:', e);
  }
}

// 异步新增数据示例
async addData() {
  if (!this.store) return;
  await this.store.put('myName', '赵云');
  await this.store.flush();
}

5. 数据量过大导致内存溢出

若存储超过 1 万条数据,会显著增加应用内存占用,建议:

  • 高频更新的大量数据改用数据库;
  • 定期清理无用数据(如过期的缓存 Key)。

五、扩展优化建议

1. 封装工具类(复用 Preferences 操作)

将 Preferences 的增删改查封装为工具类,避免重复代码:

typescript

运行

// utils/PreferencesUtil.ets
import { preferences } from '@kit.ArkData';
import { getContext } from '@kit.ArkUI';

export class PreferencesUtil {
  private static store: preferences.Preferences | null = null;

  // 初始化仓库
  public static async init(storeName: string = 'default-store') {
    if (!this.store) {
      this.store = await preferences.getPreferences(getContext(globalThis), { name: storeName });
    }
    return this.store;
  }

  // 存储数据
  public static async set(key: string, value: any) {
    if (!this.store) await this.init();
    await this.store?.put(key, value);
    await this.store?.flush();
  }

  // 读取数据
  public static async get(key: string, defaultValue: any = '') {
    if (!this.store) await this.init();
    return this.store?.get(key, defaultValue) || defaultValue;
  }

  // 删除数据
  public static async remove(key: string) {
    if (!this.store) await this.init();
    await this.store?.delete(key);
    await this.store?.flush();
  }
}

2. 添加错误处理

所有 Preferences 操作建议包裹try/catch,避免异常导致应用崩溃:

typescript

运行

Button('增加')
  .onClick(async () => {
    try {
      if (!this.store) return;
      await this.store.put('myName', '张飞');
      await this.store.flush();
      promptAction.showToast({ message: '新增成功' });
    } catch (e) {
      console.error('新增失败:', e);
      promptAction.showToast({ message: '新增失败,请重试' });
    }
  });

3. 支持数组类型存储

Preferences 支持数组类型(数字 / 字符串 / 布尔数组),示例:

typescript

运行

// 存储字符串数组
this.store.putSync('favorite_questions', ['1001', '1002', '1003']);
this.store.flush();

// 读取数组
const favorite = this.store.getSync('favorite_questions', []);
console.log('收藏的试题ID:', favorite);

六、总结

Preferences是鸿蒙应用轻量级键值存储的最佳选择,核心要点可总结为:

  1. 适用场景:仅用于存储轻量级、简单结构的数据(配置、状态标记等),避免存储大量 / 复杂数据;
  2. 核心操作:增删改查后必须调用flush(),否则数据仅存于内存,重启后丢失;
  3. 避坑重点:正确传递上下文、遵守 Key/Value 长度限制、优先使用异步 API 避免阻塞主线程;
  4. 最佳实践:封装工具类复用代码,添加错误处理,定期清理无用数据。

掌握Preferences的使用,能高效解决鸿蒙应用中轻量级数据持久化的需求,相比数据库更简洁、更高效,是 ArkTS 开发必备的基础技能之一。

Logo

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

更多推荐