鸿蒙学习实战之路-数据持久化用户首选项Preferences全攻略

最近好多朋友问我:“西兰花啊,鸿蒙应用里怎么保存用户设置才靠谱?我之前存的数据总是丢,这可咋办呢?” 害,这问题可问对人了!

今天这篇,我就手把手带你搞定鸿蒙里的用户首选项(Preferences)数据持久化,从基础概念到实战代码,全程用大白话讲明白~

一、什么是应用数据持久化?

应用数据持久化是指应用将内存中的数据通过文件或数据库的形式保存到设备上。内存中的数据形态通常是任意的数据结构或数据对象,存储介质上的数据形态可能是文本、数据库、二进制文件等。

HarmonyOS标准系统支持典型的存储数据形态,包括:

  • 用户首选项(Preferences):用于保存应用的配置信息。数据以文本形式保存在设备中,应用使用时会将文本中的数据全量加载到内存中,访问速度快、效率高,但不适合需要存储大量数据的场景。

  • 键值型数据库(KV-Store):一种非关系型数据库,其数据以"键值"对的形式进行组织、索引和存储,其中"键"作为唯一标识符。适合数据关系和业务关系较少的业务数据存储,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度和数据同步过程中冲突解决的复杂度而被广泛使用。相比于关系型数据库,更容易做到跨设备跨版本兼容。

  • 关系型数据库(RelationalStore):一种关系型数据库,以行和列的形式存储数据,广泛用于关系型数据处理,支持增、删、改、查等接口,开发者也可以运行自定义SQL语句满足复杂业务场景。此外,提供了向量数据库能力,支持向量数据间的相似度计算,适用于推荐场景、相似图像检索以及自然语言处理等。

今天咱们重点聊聊用户首选项(Preferences),这玩意儿就像咱们厨房里的调料架,专门用来放那些常用的、量不大但又离不开的小东西——比如用户的字体大小、夜间模式开关、个性化设置啥的。

二、Preferences的运作机制

咱们开发者通过ArkTS接口调用Preferences读写对应的数据文件。每个文件唯一对应到一个Preferences实例,系统通过静态容器把实例存到内存里,直到咱们主动移除或删除文件。

应用首选项的持久化文件保存在应用沙箱内部,安全得很~

图 1 用户首选项运作机制
在这里插入图片描述

三、两种存储模式,你选哪个?

Preferences有两种存储模式,就像咱们做饭用的两种锅——各有各的特点,得看需求选:

1. XML存储(默认模式)

  • 存储格式:数据以XML形式存到文件里,就像咱们写菜谱用的XML格式,通用性强
  • 优点:跨平台支持好,老设备也能用
  • 特性:操作主要在内存里进行,得手动喊一声"flush"才会保存到磁盘(就像炒菜得手动关火一样)
  • 适用场景:单进程、小数据量的情况,比如单个页面的设置保存

2. GSKV存储(高级模式)

  • 存储格式:数据以二进制形式存储(API 18起支持,就像用保鲜袋封装食材,更紧凑)
  • 优点:支持多进程并发读写,适合复杂应用
  • 特性:操作会实时保存到磁盘,不用手动flush(就像用自动断电的电磁炉,安全又省心)
  • 适用场景:多进程并发的场景,比如需要在多个页面间共享数据的应用

🥦 西兰花警告
GSKV模式虽然好用,但不是所有平台都支持!使用前一定要先检查平台是否支持哦~

四、注意事项要牢记

Preferences虽然好用,但也有一些"家规"得遵守,不然容易出问题:

通用限制

  • Key键必须是字符串,不能空,长度不能超过1024字节(别起太长的名字)
  • Value如果是字符串,得用UTF-8编码,最长不能超过16MB(别存太大的东西)
  • 调用removePreferencesFromCachedeletePreferences后,要重新订阅数据变更
  • deletePreferences别和其他接口一起多线程/多进程调用
  • 不支持自动加密,敏感数据得自己加密后用Uint8Array类型存储

XML模式特别注意

  • 不支持多进程!强行用的话可能会损坏文件或丢失数据(就像多人同时用一个锅炒菜,肯定得糊)
  • 非UTF-8字符串得转成Uint8Array类型存储
  • 建议存储的数据量别超过50MB,不然可能会卡住(就像冰箱塞太满门都关不上)

GSKV模式特别注意

  • 不支持跨平台,用之前先检查平台支持性

🥦 西兰花小贴士
如果你的应用需要在多个进程间共享数据,优先考虑GSKV模式,省心又安全!

五、核心接口速览

Preferences提供了一套简单好用的接口,咱们来快速认识一下:

接口名称 描述
getPreferencesSync 获取Preferences实例(也有异步版本)
putSync 写入数据(也有异步版本)
hasSync 检查是否包含指定Key(也有异步版本)
getSync 读取数据,可设置默认值(也有异步版本)
deleteSync 删除指定键值对(也有异步版本)
flush 异步将数据持久化到文件(XML模式需要)
on('change') 订阅数据变更
off('change') 取消订阅数据变更
deletePreferences 删除Preferences实例及文件
isStorageTypeSupported 判断平台是否支持指定存储模式

六、实战代码走起来

光说不练假把式,咱们直接上代码!

1. 导入模块

首先得把Preferences模块导入进来:

import { preferences } from "@kit.ArkData";

2. 检查存储模式支持性

如果想用GSKV模式,得先检查平台支不支持:

// 判断当前平台是否支持GSKV模式
let isGskvSupported = preferences.isStorageTypeSupported(
  preferences.StorageType.GSKV
);
console.info("当前平台是否支持GSKV模式: " + isGskvSupported);

3. 获取Preferences实例

接下来得拿到Preferences的实例,就像拿到咱们的调料罐一样:

XML模式(默认):

import { UIAbility } from "@kit.AbilityKit";
import { window } from "@kit.ArkUI";

// 定义一个全局变量保存Preferences实例
let dataPreferences: preferences.Preferences | null = null;

class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) {
    // 配置选项,name是存储文件的名称
    let options: preferences.Options = { name: "userSettings" };
    // 同步获取Preferences实例
    dataPreferences = preferences.getPreferencesSync(this.context, options);
  }
}

GSKV模式:

// 如果支持GSKV模式,就用它
if (isGskvSupported) {
  let options: preferences.Options = {
    name: "userSettings",
    storageType: preferences.StorageType.GSKV, // 指定使用GSKV模式
  };
  dataPreferences = preferences.getPreferencesSync(this.context, options);
}

4. 写入数据

现在可以往Preferences里存数据了,就像往调料罐里放调料一样:

import { util } from "@kit.ArkTS";

// 先检查键是否已存在
if (dataPreferences.hasSync("fontSize")) {
  console.info("字体大小设置已存在");
} else {
  // 写入字符串数据(比如字体大小)
  dataPreferences.putSync("fontSize", "medium");
  
  // 写入夜间模式设置
  dataPreferences.putSync("nightMode", false);
  
  // 写入非UTF-8字符串(比如特殊符号)
  let specialChars = new util.TextEncoder().encodeInto("~!@#¥%……&*()——+");
  dataPreferences.putSync("specialSettings", specialChars);
}

5. 读取数据

存进去的数据得能读出来才行,就像做饭时得知道用哪种调料:

// 读取字体大小设置,默认值为"medium"
let fontSize = dataPreferences.getSync("fontSize", "medium");
console.info("当前字体大小: " + fontSize);

// 读取夜间模式设置,默认值为false
let nightMode = dataPreferences.getSync("nightMode", false);
console.info("是否开启夜间模式: " + nightMode);

// 读取特殊符号设置并转换为字符串
let specialSettings: preferences.ValueType = dataPreferences.getSync(
  "specialSettings",
  new Uint8Array(0)
);
let textDecoder = util.TextDecoder.create("utf-8");
let specialStr = textDecoder.decodeToString(specialSettings as Uint8Array);
console.info("特殊设置: " + specialStr);

6. 删除数据

不需要的数据可以删掉,就像清理过期的调料:

// 删除不再需要的设置
if (dataPreferences.hasSync("oldSetting")) {
  dataPreferences.deleteSync("oldSetting");
  console.info("已删除旧设置");
}

7. 数据持久化(XML模式专用)

如果用的是XML模式,得手动保存数据到磁盘,就像做饭完了要关火:

// 将内存中的数据保存到磁盘
if (!isGskvSupported) {
  dataPreferences.flush((err) => {
    if (err) {
      console.error(`保存失败: ${err.code}, ${err.message}`);
      return;
    }
    console.info("数据已成功保存到磁盘");
  });
}

8. 订阅数据变更

想实时知道数据有没有变化?可以订阅数据变更事件:

XML模式:

// 定义数据变更的观察者
let observer = (key: string) => {
  console.info(`设置${key}发生了变化`);
};

// 订阅数据变更
if (dataPreferences) {
  dataPreferences.on("change", observer);
  
  // 修改数据并手动flush才会触发变更通知
  dataPreferences.put("fontSize", "large", (err) => {
    if (!err) {
      dataPreferences.flush(() => {});
    }
  });
}

GSKV模式:

// 定义数据变更的观察者
let observer = (key: string) => {
  console.info(`设置${key}发生了变化`);
};

// 订阅数据变更
if (dataPreferences && isGskvSupported) {
  dataPreferences.on("change", observer);
  
  // 修改数据会自动触发变更通知,不用手动flush
  dataPreferences.put("fontSize", "large", (err) => {});
}

9. 删除指定文件

如果不想用某个Preferences文件了,可以删掉它:

// 删除Preferences实例及对应的文件
let options: preferences.Options = { name: "userSettings" };
preferences.deletePreferences(this.context, options, (err) => {
  if (err) {
    console.error(`删除失败: ${err.code}, ${err.message}`);
    return;
  }
  console.info("已成功删除Preferences文件");
  // 记得清空实例引用
  dataPreferences = null;
});

七、完整示例代码

想直接用的朋友,可以参考官方的完整示例:首选项示例

八、总结一下

今天咱们一起学习了鸿蒙里的用户首选项(Preferences)数据持久化,从基础概念到实战代码,相信你已经掌握了:

  1. 什么是应用数据持久化,以及HarmonyOS支持的三种存储方式
  2. Preferences的两种存储模式(XML和GSKV)的区别和适用场景
  3. 使用Preferences的注意事项和限制
  4. 如何使用Preferences进行数据的增删改查
  5. 如何订阅数据变更和管理Preferences实例

🥦 西兰花小贴士
Preferences适合保存轻量级的配置信息,如果你需要存储大量结构化数据,建议考虑使用关系型数据库(RelationalStore)哦~

📚 推荐资料:

我是盐焗西兰花,
不教理论,只给你能跑的代码和避坑指南。
下期见!🥦

Logo

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

更多推荐