目录
一、HarmonyOS 用户首选项是什么?
二、开发前的准备工作
(一)开发环境搭建
(二)相关概念理解
三、开发流程详细步骤
(一)获取 Preferences 实例
(二)数据操作方法
1. 写入数据
2. 读取数据
3. 删除数据
(三)数据持久化与变更订阅
1. 数据持久化
2. 订阅数据变更
四、开发案例实操
(一)案例背景与需求
(二)代码实现过程
1. 自定义用户首选项类
2. UI 界面设计
(三)案例效果展示
五、开发注意事项
(一)数据大小与类型限制
(二)内存与并发安全限制
六、总结与展望
一、HarmonyOS 用户首选项是什么?

HarmonyOS 用户首选项为应用提供了一种 Key – Value 键值型的数据处理能力,主要用于保存应用配置、用户偏好等轻量级数据。比如,我们日常使用的应用中,用户设置的字体大小、主题模式(白天 / 黑夜模式)、是否接收推送通知 等信息,都可以通过用户首选项来存储。
它将数据以键值对的形式存储,其中键(Key)是用于标识数据的唯一字符串,值(Value)则是对应的数据内容 ,可以是数字、字符串、布尔值等基本数据类型,以及这些类型的数组 。而且,这些数据不仅会缓存在内存中,方便快速读取,还能通过特定操作持久化到本地文件,保证应用关闭再重启后数据不丢失。这一特性使得用户首选项在存储一些频繁读取和修改的小型数据时非常高效 ,能有效提升应用的响应速度和用户体验。
二、开发前的准备工作
(一)开发环境搭建
在开始 HarmonyOS 用户首选项的开发之前,我们需要先搭建好开发环境。
软件要求:确保你的开发环境中安装了 DevEco Studio 3.1 Release 及以上版本 ,这是 HarmonyOS 应用开发的官方集成开发环境(IDE),提供了丰富的工具和功能,能大大提高开发效率。同时,需要下载并配置 OpenHarmony SDK API version 9 及以上版本 ,它包含了开发 HarmonyOS 应用所需的各种库和工具。
硬件要求:如果你使用开发板进行真机调试,需要准备符合条件的硬件开发板 ,如润和 RK3568 开发板等,并确保其运行的 OpenHarmony 系统版本为 3.2 Release 及以上。
环境搭建步骤:首先,从华为开发者联盟官网下载 DevEco Studio 安装包 ,根据安装向导进行安装。安装完成后,打开 DevEco Studio,在欢迎页面选择 “Configure” -> “Settings”,在弹出的窗口中选择 “Appearance & Behavior” -> “System Settings” -> “HTTP Proxy”,配置网络代理(如果需要的话)。接着,在 “SDK Manager” 中下载并安装所需的 OpenHarmony SDK 。下载完成后,SDK 会自动配置到 DevEco Studio 中。
(二)相关概念理解
dialog(自定义弹窗容器):在 HarmonyOS 应用开发中,dialog 是一种常用的 UI 组件,用于创建自定义弹窗 。它可以用来展示用户当前需要或必须已关注的信息,比如提示用户保存设置成功、询问用户是否确认退出应用等。dialog 仅支持 width、height、margin 等部分样式,且仅支持单个子组件,属性、样式均不支持动态更新 ,也不支持 focusable、click – effect 属性。例如,在用户点击保存用户首选项设置的按钮后,可以弹出一个 dialog 提示用户 “设置已保存” 。
用户首选项:如前文所述,用户首选项是一种以 Key – Value 键值对形式存储数据的方式 ,用于保存应用配置、用户偏好等轻量级数据。理解用户首选项的工作原理和使用场景,对于后续的开发至关重要。比如,我们要开发一个阅读应用,用户设置的字体大小、行间距、是否开启夜间模式等信息,就可以通过用户首选项来存储和管理 。
三、开发流程详细步骤
(一)获取 Preferences 实例
在 HarmonyOS 中获取 Preferences 实例,不同的应用模型有不同的实现方式 。
Stage 模型:首先,需要导入相关模块,代码如下:
import UIAbility from '@ohos.app.ability.UIAbility';
import { BusinessError } from '@ohos.base';
import window from '@ohos.window';
import dataPreferences from '@ohos.data.preferences';
然后,在UIAbility的onWindowStageCreate生命周期方法中获取Preferences实例 :
let preferences: dataPreferences.Preferences | null = null;
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
let options: dataPreferences.Options = { name:'myStore' };
preferences = dataPreferences.getPreferencesSync(this.context, options);
}
}
这里的options是一个配置对象 ,其中name属性用于指定Preferences实例的名称,通过getPreferencesSync方法同步获取Preferences实例,它会返回一个Preferences对象,后续我们就可以使用这个对象对用户首选项数据进行操作 。
FA 模型:同样先导入必要的模块 :
import featureAbility from '@ohos.ability.featureAbility';
import { BusinessError } from '@ohos.base';
import dataPreferences from '@ohos.data.preferences';
接着获取context并通过getPreferencesSync方法获取Preferences实例 :
let context = featureAbility.getContext();
let options: dataPreferences.Options = { name:'myStore' };
let preferences: dataPreferences.Preferences = dataPreferences.getPreferencesSync(context, options);
在 FA 模型中,通过featureAbility.getContext()获取应用上下文context ,再利用context和配置选项options来获取Preferences实例 。
(二)数据操作方法
获取到Preferences实例后,就可以对其中的数据进行写入、读取和删除等操作 。
1. 写入数据
使用putSync()方法可以将数据保存到缓存的Preferences实例中 。如果要确保数据持久化存储到文件中,在写入数据后,需要调用flush()方法 。示例代码如下 :
import util from '@ohos.util';
if (preferences.hasSync('startup')) {
console.info("The key'startup' is contained.");
} else {
console.info("The key'startup' does not contain.");
// 此处以此键值对不存在时写入数据为例
preferences.putSync('startup', 'auto');
// 当字符串有特殊字符时,需要将字符串转为Uint8Array类型再存储
let uInt8Array = new util.TextEncoder().encodeInto("~!@#¥%……&*()——+?");
preferences.putSync('uInt8', uInt8Array);
}
上述代码中,首先通过hasSync()方法检查startup这个键是否已经存在于Preferences实例中 。如果不存在,则使用putSync()方法写入数据 。对于包含特殊字符的字符串,需要先将其转换为Uint8Array类型再进行存储 。
2. 读取数据
使用getSync()方法可以获取指定键对应的值 。如果该键不存在,或者对应的值为null或者非默认值类型,则返回传入的默认数据 。示例代码如下 :
import util from '@ohos.util';
let val = preferences.getSync('startup', 'default');
console.info("The'startup' value is " + val);
// 当获取的值为带有特殊字符的字符串时,需要将获取到的Uint8Array转换为字符串
let uInt8Array : dataPreferences.ValueType = preferences.getSync('uInt8', new Uint8Array(0));
let textDecoder = util.TextDecoder.create('utf-8');
val = textDecoder.decodeWithStream(uInt8Array as Uint8Array);
console.info("The 'uInt8' value is " + val);
这里通过getSync('startup', 'default')获取startup键对应的值,如果没有找到该键,则返回默认值default 。对于之前存储的特殊字符字符串,在获取时需要将得到的Uint8Array类型数据转换回字符串 。
3. 删除数据
使用deleteSync()方法可以删除指定键值对 。示例代码如下 :
preferences.deleteSync('startup');
执行上述代码后,startup键及其对应的值就会从Preferences实例中被删除 。需要注意的是,一旦删除,数据将无法恢复 ,并且如果后续还依赖该数据进行某些操作,可能会导致程序出现异常,所以在执行删除操作时要谨慎确认 。
(三)数据持久化与变更订阅
1. 数据持久化
当我们向Preferences实例中存入数据后,数据只是先缓存在内存中 。为了让数据在应用关闭后也能保存下来,需要使用flush()方法将数据持久化到本地文件 。示例代码如下 :
preferences.flush((err: BusinessError) => {
if (err) {
console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
return;
}
console.info('Succeeded in flushing.');
});
flush()方法是异步操作,通过传入一个回调函数来处理操作结果 。如果操作失败,回调函数中的err参数会包含错误信息 ;如果成功,会打印出成功信息 。
2. 订阅数据变更
应用可以通过订阅数据变更来监听Preferences实例中数据的变化 。具体做法是指定一个observer作为回调方法 。当订阅的 Key 值发生变更,并且执行flush()方法时,observer会被触发回调 。示例代码如下 :
let observer = (key: string) => {
console.info('The key'+ key + 'changed.');
}
preferences.on('change', observer);
// 数据产生变更,由'auto'变为'manual'
preferences.put('startup','manual', (err: BusinessError) => {
if (err) {
console.error(`Failed to put the value of'startup'. Code:${err.code},message:${err.message}`);
return;
}
console.info("Succeeded in putting the value of'startup'.");
if (preferences!== null) {
preferences.flush((err: BusinessError) => {
if (err) {
console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
return;
}
console.info('Succeeded in flushing.');
});
}
});
上述代码中,首先定义了一个observer回调函数,它会在数据变更时打印出变更的键 。然后使用preferences.on('change', observer)来订阅数据变更 。当通过preferences.put('startup','manual'…方法改变startup键对应的值,并在执行flush()方法后,observer回调函数就会被触发 ,从而得知数据发生了变化 。
四、开发案例实操
(一)案例背景与需求
在许多应用中,屏幕亮度设置是一个常见的功能。为了给用户提供个性化的使用体验,我们需要实现一个屏幕亮度设置功能,并且将用户设置的亮度值通过 HarmonyOS 的用户首选项进行存储、读取和删除操作。这样,当用户下次打开应用时,能够直接恢复到上次设置的亮度 ,并且在用户想要重置亮度设置时,可以删除已保存的亮度数据。
(二)代码实现过程
1. 自定义用户首选项类
首先,我们自定义一个用户首选项类PreferenceModel,在这个类中封装获取用户首选项实例、删除数据、保存数据、获取数据等方法 ,方便后续在业务逻辑中调用。
import dataPreferences from '@ohos.data.preferences';
import promptAction from '@ohos.promptAction';
import ScreenBrightness from '../common/bean/Brightness';
// 获取应用上下文
let context = getContext(this);
// 定义用户首选项实例
let preference: dataPreferences.Preferences = null;
// 自定义用户首选项类
class PreferenceModel {
// 存储屏幕亮度数据的属性
private brightness: ScreenBrightness;
// 创建用户首选项实例
async getPreferencesFromStorage() {
try {
// 获取名为'setting.db'的用户首选项实例
preference = await dataPreferences.getPreferences(context,'setting.db');
} catch (err) {
console.error('[PreferenceModel]', `Failed to get preferences, Cause: ${err}`);
}
}
// 删除数据,调用dataPreferences的deletePreferences接口
async deletePreferences() {
try {
// 删除名为'setting.db'的用户首选项实例及其持久化文件
await dataPreferences.deletePreferences(context,'setting.db');
} catch (err) {
console.error('[PreferenceModel]', `Failed to delete preferences, Cause: ${err}`);
}
// 将用户首选项实例置为null
preference = null;
// 显示删除成功的提示消息
this.showToastMessage($r('app.string.delete_success_msg'));
}
// 保存数据
async putPreference(screenBrightness: ScreenBrightness) {
if (preference === null) {
// 如果用户首选项实例为空,先获取实例
await this.getPreferencesFromStorage();
}
// 将用户输入的亮度数据保存到preference,调用用户首选项实例的put接口
try {
await preference.put('screenBrightness', JSON.stringify(screenBrightness));
} catch (err) {
console.error('[PreferenceModel]', `Failed to put value, Cause: ${err}`);
}
// 使用flush方法将preferences实例的数据存储到持久化文件,调用用户首选项实例的flush接口
await preference.flush();
}
// 获取数据,调用用户首选项实例的get接口
async getPreference() {
let screenBrightness = '';
if (preference === null) {
// 如果用户首选项实例为空,先获取实例
await this.getPreferencesFromStorage();
}
try {
// 获取'screenBrightness'键对应的值
screenBrightness = <string>await preference.get('screenBrightness', '');
} catch (err) {
console.error('[PreferenceModel]', `Failed to get value, Cause: ${err}`);
}
// 如果判断数据为空则提示用户先输入数据
if (screenBrightness === '') {
this.showToastMessage($r('app.string.data_is_null_msg'));
return;
}
// 显示读取成功的提示消息
this.showToastMessage($r('app.string.read_success_msg'));
// 将获取到的JSON字符串转换为对象并返回
return JSON.parse(screenBrightness);
}
// 校验用户输入是否为空
checkData(screenBrightness: ScreenBrightness) {
if (screenBrightness.brightSwitch === '' || screenBrightness.defaultValue === '') {
this.showToastMessage($r('app.string.fruit_input_null_msg'));
return true;
}
return false;
}
// 点击保存按钮保存数据
writeData(screenBrightness: ScreenBrightness) {
// 检查数据是否为空
let isDataNull = this.checkData(screenBrightness);
if (isDataNull) {
return;
}
// 如果数据不为空,将数据插入到用户首选项数据库
this.putPreference(screenBrightness);
// 显示写入成功的提示消息
this.showToastMessage($r('app.string.write_success_msg'));
}
// 消息弹框
showToastMessage(message: Resource) {
promptAction.showToast({
message: message,
duration: 3000
});
}
}
2. UI 界面设计
UI 界面主要包含两大部分:文本和输入框用于用户输入亮度相关数据 ;按钮用于触发保存、读取和删除数据的操作 。为了使代码结构更加清晰,我们将这两部分分别抽取为子组件,在主页中进行调用 。
// 导入相关模块
import dataPreferences from '@ohos.data.preferences';
import promptAction from '@ohos.promptAction';
import { Resource } from '@ohos.resource';
// 导入自定义的用户首选项类
import PreferenceModel from '../model/PreferenceModel';
// 导入屏幕亮度数据模型
import ScreenBrightness from '../common/bean/Brightness';
// 创建用户首选项类的实例
let preferenceModel = new PreferenceModel();
// 定义屏幕亮度数据变量
let screenBrightness: ScreenBrightness = {
brightSwitch: '',
defaultValue: ''
};
@Entry
@Component
struct Index {
// 用于标识输入框聚焦状态的变量
@FocusState private focusState: boolean = false;
build() {
Column() {
// 调用自定义的文本输入框子组件
TextInputComponent('亮度开关', this.focusState, (value) => {
screenBrightness.brightSwitch = value;
});
// 调用自定义的文本输入框子组件
TextInputComponent('默认亮度值', this.focusState, (value) => {
screenBrightness.defaultValue = value;
});
Row() {
// 调用自定义的按钮子组件,点击时触发保存数据操作
ButtonComponent('保存数据', () => {
preferenceModel.writeData(screenBrightness);
});
// 调用自定义的按钮子组件,点击时触发读取数据操作
ButtonComponent('读取数据', async () => {
let result = await preferenceModel.getPreference();
if (result) {
screenBrightness = result;
}
});
// 调用自定义的按钮子组件,点击时触发删除数据操作
ButtonComponent('删除数据', () => {
preferenceModel.deletePreferences();
});
}
}
.width('100%')
.height('100%')
.padding(20);
}
}
// 自定义的文本输入框子组件
@Component
struct TextInputComponent {
// 输入框的提示文本
placeholder: string;
// 输入框的聚焦状态
@FocusState private focusState: boolean;
// 输入框内容变化时的回调函数
onChange: (value: string) => void;
build() {
TextInput({ placeholder: this.placeholder })
.width('100%')
.height(50)
.fontSize(16)
.padding({ left: 10 })
.backgroundColor(this.focusState? Color.LightGray : Color.White)
.onChange((value) => {
this.onChange(value);
})
.onFocus((isFocus) => {
this.focusState = isFocus;
});
}
}
// 自定义的按钮子组件
@Component
struct ButtonComponent {
// 按钮的文本
buttonText: string;
// 按钮点击时的回调函数
onClick: () => void;
build() {
Button(this.buttonText)
.width(120)
.height(40)
.fontSize(16)
.backgroundColor(Color.Blue)
.fontColor(Color.White)
.margin(10)
.onClick(this.onClick);
}
}
(三)案例效果展示
保存数据:当用户在文本输入框中输入屏幕亮度开关状态(如 “开” 或 “关” )和默认亮度值(如 “50” ),点击 “保存数据” 按钮后 ,数据会通过putPreference方法保存到用户首选项中 。此时,会弹出一个提示框显示 “写入成功” ,提示用户数据已成功保存 。
读取数据:点击 “读取数据” 按钮 ,应用会调用getPreference方法从用户首选项中获取之前保存的屏幕亮度数据 。如果获取成功,会弹出提示框显示 “读取成功” ,并且输入框中的内容会更新为获取到的数据 。
删除数据:点击 “删除数据” 按钮 ,应用会调用deletePreferences方法删除用户首选项中保存的屏幕亮度数据 。操作完成后,会弹出提示框显示 “删除成功” ,此时再点击 “读取数据” 按钮,由于数据已被删除,会弹出提示框显示 “请先输入数据” 。
五、开发注意事项
(一)数据大小与类型限制
在 HarmonyOS 用户首选项开发中,数据的大小和类型有着明确的限制。
Key 的长度限制:Key 为 string 类型,必须是非空的,并且其长度不能超过 1024 字节。这意味着我们在定义 Key 时,要尽量简洁明了地表达数据的含义 ,同时避免使用过长的字符串作为 Key。例如,在存储用户的主题设置时,可以使用 “theme_mode” 作为 Key,而不是冗长的 “user_selected_theme_mode_in_the_application” ,这样既能满足数据标识的需求,又不会超出长度限制 。
Value 的长度和类型限制:如果 Value 值为 string 类型,需采用 UTF – 8 编码格式,它可以为空,若不为空时,长度不能超过 16MB 。当存储的数据中包含非 UTF – 8 格式的字符串时,应使用 Uint8Array 类型存储 ,否则可能会造成持久化文件出现格式错误,进而导致文件损坏 。Value 支持的数据类型包括 number、string、boolean、Array、Array、Array、Uint8Array、object、bigint 。在选择 Value 的数据类型时,要根据实际数据内容进行合理选择。比如,存储用户的年龄时,使用 number 类型;存储用户是否同意隐私协议时,使用 boolean 类型 。
(二)内存与并发安全限制
内存限制:用户首选项会将数据缓存在内存中,随着存储数据量的不断增加,应用占用的内存也会随之增大 。因此,它并不适合存储过多的数据,建议存储的数据量不超过一万条 ,否则可能会在内存方面产生较大的开销,影响应用的性能,导致应用运行缓慢甚至出现卡顿现象 。例如,一个简单的设置类应用,使用用户首选项存储用户的一些基本设置,如字体大小、是否开启音效等少量数据是合适的;但如果尝试用它来存储大量的用户操作历史记录,就会导致内存占用过高,应用性能下降 。
并发安全限制:用户首选项无法保证进程并发安全,存在文件损坏和数据丢失的风险 ,所以不支持在多进程场景下使用 。如果在多进程环境中同时对用户首选项进行读写操作,可能会出现数据不一致、文件损坏等不可预期的问题 。比如,当一个进程正在写入数据时,另一个进程同时进行读取或写入操作,就可能导致读取到的数据不完整,或者写入的数据被覆盖、文件结构被破坏等情况 。在开发过程中,如果应用涉及多进程,就需要考虑其他更适合多进程场景的数据存储方案 ,如使用分布式数据管理服务等 。
六、总结与展望
HarmonyOS 用户首选项开发流程从获取 Preferences 实例开始,通过特定的方法进行数据的写入、读取和删除操作,同时要注意数据的持久化和变更订阅 。在开发过程中,严格遵循数据大小与类型限制以及内存与并发安全限制,能有效避免数据存储和读取错误,提升应用的稳定性和性能 。
随着 HarmonyOS 生态的不断发展和完善,用户首选项在更多类型的应用中都将发挥重要作用 。无论是工具类应用中用户对功能开关的设置,还是社交类应用中用户对隐私权限的偏好选择 ,都可以借助用户首选项来实现高效的数据存储与管理 。
如果你对 HarmonyOS 应用开发感兴趣,不妨亲自尝试一下用户首选项的开发 。通过实际动手,你将更深入地理解其原理和优势,为开发出更优质、更贴合用户需求的 HarmonyOS 应用奠定坚实的基础 。
















暂无评论内容