【Flutter for OpenHarmony 】:第三方库+Preferences本地存储实现主题记忆+数据持久化
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
🍭前言
在鸿蒙应用开发中,数据持久化是必备能力。轻量级存储 Preferences 常用于保存主题模式、用户配置、开关状态等小数据。
本文将从开发目的 → 架构设计 → 标准开发流程 → 代码实现 → 功能测试 → 深度踩坑完整复盘,带你从零实现一套可直接上线、无报错、重启记忆的主题存储+用户名管理功能。
🍧一、开发目的与需求说明
1. 1.1 核心目标
掌握鸿蒙 @ohos.data.preferences 轻量级存储使用
实现亮/暗黑主题切换,关闭重启自动记忆
实现用户名存储、读取、清空功能
封装通用工具类,做到全局复用、结构清晰
规避异步时序、语法报错、数据丢失等真实开发坑点
1. 1.2 适用场景
主题模式保存
用户偏好设置
登录状态记录
小型配置持久化
1. 1.3 技术栈
开发框架:鸿蒙 ArkTS
存储组件:Preferences
架构模式:单例工具类 + 页面状态管理
运行环境:DevEco Studio + 鸿蒙模拟器/真机
🍬二、项目架构设计
1. 2.1 项目结构
entry/src/main/ets/
├── entryability/EntryAbility.ets # 应用入口(全局初始化存储)
├── pages/Index.ets # 主页面(UI渲染+业务逻辑)
└── utils/PreferencesUtil.ets # 存储工具类(单例封装)
1. 2.2 架构思路
工具层:统一封装 Preferences 增删改查,保证全局唯一实例
入口层:应用启动时初始化存储,注入上下文
页面层:实现交互逻辑、状态管理、动态UI渲染
🍫三、标准开发流程
步骤 1:封装 Preferences 工具类
目的:避免重复代码、防止多实例冲突、统一处理异步与flush。
代码如下:
import preferences from '@ohos.data.preferences';
import common from '@ohos.app.ability.common';
const STORE_NAME: string = 'app_config';
class PreferencesUtil {
private static instance: PreferencesUtil | null = null;
private dataPreferences: preferences.Preferences | null = null;
private context: common.UIAbilityContext | null = null;
private constructor() {}
public static getInstance(): PreferencesUtil {
if (PreferencesUtil.instance === null) {
PreferencesUtil.instance = new PreferencesUtil();
}
return PreferencesUtil.instance;
}
public init(context: common.UIAbilityContext): void {
this.context = context;
preferences.getPreferences(context, STORE_NAME, (err, data) => {
if (err) {
console.error('Preferences初始化失败:', JSON.stringify(err));
return;
}
this.dataPreferences = data;
console.info('Preferences初始化成功');
});
}
public putString(key: string, value: string): Promise<void> {
return new Promise((resolve, reject) => {
if (!this.dataPreferences) {
reject(new Error('Preferences未初始化'));
return;
}
this.dataPreferences.put(key, value, (err) => {
if (err) {
reject(err);
return;
}
this.dataPreferences?.flush((flushErr) => {
if (flushErr) {
reject(flushErr);
return;
}
resolve();
});
});
});
}
public getString(key: string, defaultValue: string = ''): Promise<string> {
return new Promise((resolve, reject) => {
if (!this.dataPreferences) {
reject(new Error('Preferences未初始化'));
return;
}
this.dataPreferences.get(key, defaultValue, (err, value) => {
if (err) {
reject(err);
return;
}
resolve(value as string);
});
});
}
public putBool(key: string, value: boolean): Promise<void> {
return new Promise((resolve, reject) => {
if (!this.dataPreferences) {
reject(new Error('Preferences未初始化'));
return;
}
this.dataPreferences.put(key, value, (err) => {
if (err) {
reject(err);
return;
}
this.dataPreferences?.flush((flushErr) => {
if (flushErr) {
reject(flushErr);
return;
}
resolve();
});
});
});
}
public getBool(key: string, defaultValue: boolean = false): Promise<boolean> {
return new Promise((resolve, reject) => {
if (!this.dataPreferences) {
reject(new Error('Preferences未初始化'));
return;
}
this.dataPreferences.get(key, defaultValue, (err, value) => {
if (err) {
reject(err);
return;
}
resolve(value as boolean);
});
});
}
public delete(key: string): Promise<void> {
return new Promise((resolve, reject) => {
if (!this.dataPreferences) {
reject(new Error('Preferences未初始化'));
return;
}
this.dataPreferences.delete(key, (err) => {
if (err) {
reject(err);
return;
}
this.dataPreferences?.flush((flushErr) => {
if (flushErr) {
reject(flushErr);
return;
}
resolve();
});
});
});
}
public clear(): Promise<void> {
return new Promise((resolve, reject) => {
if (!this.dataPreferences) {
reject(new Error('Preferences未初始化'));
return;
}
this.dataPreferences.clear((err) => {
if (err) {
reject(err);
return;
}
this.dataPreferences?.flush((flushErr) => {
if (flushErr) {
reject(flushErr);
return;
}
resolve();
});
});
});
}
}
export default PreferencesUtil.getInstance();
步骤 2:应用入口初始化
目的:应用启动时完成存储初始化,保证页面调用时已就绪。
代码如下:
import PreferencesUtil from '../utils/PreferencesUtil';
struct Index {
isDarkMode: boolean = false;
username: string = '未存储';
async aboutToAppear() {
const darkMode = await PreferencesUtil.getBool('isDarkMode', false);
this.isDarkMode = darkMode;
const name = await PreferencesUtil.getString('username', '未存储');
this.username = name;
}
async toggleTheme() {
this.isDarkMode = !this.isDarkMode;
await PreferencesUtil.putBool('isDarkMode', this.isDarkMode);
}
async saveUsername() {
const name = '鸿蒙ArkTS小白';
await PreferencesUtil.putString('username', name);
this.username = name;
}
async loadUsername() {
const name = await PreferencesUtil.getString('username', '未存储');
this.username = name;
}
async clearAll() {
await PreferencesUtil.clear();
this.isDarkMode = false;
this.username = '已清空';
}
build() {
Column() {
Text(this.isDarkMode ? '🌙 当前:暗黑模式' : '☀️ 当前:明亮模式')
.fontSize(22)
.fontWeight(FontWeight.Bold)
.fontColor(this.isDarkMode ? Color.White : Color.Black)
.margin({ bottom: 30 })
Button('切换主题')
.width(200)
.height(50)
.fontSize(18)
.margin({ bottom: 60 })
.onClick(() => this.toggleTheme())
Text('存储用户名演示')
.fontSize(16)
.fontColor(this.isDarkMode ? Color.White : Color.Black)
.margin({ bottom: 15 })
Button('存储用户名')
.width(180)
.height(45)
.margin({ bottom: 10 })
.onClick(() => this.saveUsername())
Button('读取用户名')
.width(180)
.height(45)
.margin({ bottom: 20 })
.onClick(() => this.loadUsername())
Text(`当前名字:${this.username}`)
.fontSize(14)
.fontColor(this.isDarkMode ? Color.White : Color.Black)
.opacity(0.7)
Button('清空所有存储')
.width(180)
.height(40)
.backgroundColor(Color.Red)
.margin({ top: 40 })
.onClick(() => this.clearAll())
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor(this.isDarkMode ? Color.Black : Color.White)
}
}
🍨四、运行结果与功能测试
4.1 运行成功界面
运行成功
编译输出:BUILD SUCCESSFUL
页面正常显示,无报错、无闪退、无样式错乱
4.2 功能测试清单
初始状态:明亮模式,用户名=未存储 ✅
主题切换:点击切换亮/暗,实时生效 ✅
重启记忆:关闭App重新打开,主题保持不变 ✅
存储用户名:点击后保存并显示指定昵称 ✅
读取用户名:从本地重新加载数据 ✅
清空存储:恢复默认状态,数据清空 ✅
🍹五、开发过程避坑指南
🤔坑 1:put 不调用 flush → 数据必丢失
原因:put 只写入内存,flush 才持久化到文件
解决方案:所有写操作后必须执行 flush()
🤔坑 2:异步初始化时序错乱 → 页面调用报 null
原因:页面 aboutToAppear 执行比初始化快
解决方案:使用 initPromise 强制等待初始化完成
🤔坑 3:const 变量在 ArkTS 中极易报红
原因:ArkTS 对作用域、类型推断比 TS 更严格
解决方案:直接内联三元表达式,不单独声明变量
🤔坑 4:单例模式错误 → 多实例数据混乱
原因:多次创建实例、重复初始化
解决方案:构造函数私有化 + 全局唯一 instance
🤔坑 5:上下文传错 → 存储不生效
原因:使用页面上下文而非 Ability 上下文
解决方案:统一在 EntryAbility 传入 this.context
🤔坑 6:同步异步混用 → 界面卡顿
原因:同步IO阻塞主线程
解决方案:全程使用 async/await 异步写法
🎂运行结果如下:

六、实践总结
Preferences 只适合轻量数据
工具类必须单例设计
写操作必须 flush
优先内联样式,减少变量声明
全局捕获异常,避免崩溃
初始化放在 Ability 生命周期
七、结语
本文完整实现了鸿蒙 ArkTS 下 Preferences 本地存储 标准开发流程,从架构、代码、测试到避坑全覆盖。
这套方案可直接用于课程设计、结课作业、上线项目,是鸿蒙开发必备基础技能。
更多推荐



所有评论(0)