HarmonyOs应用《重要日》开发第6篇 - 数据持久化存储
本篇深入剖析 ImportantDays 项目的数据持久化方案——基于 HarmonyOS ArkData 模块的 Preferences 轻量级存储以及 PreferenceUtil 工具类的单例封装。一、HarmonyOS 数据存储方案对比HarmonyOS 提供了多种数据存储方案方案适用场景特点Preferences轻量级 KV 数据同步操作适合少量数据关系型数据库 (RDB)结构化数据SQLite支持复杂查询分布式数据 (DDS)跨设备同步多设备数据一致性文件存储大文件直接读写文件系统ImportantDays 选择 Preferences 的原因数据量小通常几十条重要日数据结构简单JSON 字符串不需要复杂查询同步操作代码简洁二、PreferenceUtil 工具类2.1 完整实现// utils/PreferenceUtil.etsimport{preferences}fromkit.ArkData;import{common}fromkit.AbilityKit;import{Logger}from./Logger;exportclassPreferenceUtil{privatestaticpreferenceRecord:Mapstring,PreferenceUtilnewMap();privatedataPreferences:preferences.Preferences|nullnull;privateconstructor(context:Context,fileName:string){preferences.removePreferencesFromCacheSync(context,fileName);this.dataPreferencespreferences.getPreferencesSync(context,{name:fileName});Logger.info(PreferenceUtil:${fileName}init:${this.dataPreferences!null});}publicstaticgetInstance(context?:Context,fileName:stringdefault):PreferenceUtil{if(PreferenceUtil.preferenceRecord.has(fileName)){returnPreferenceUtil.preferenceRecord.get(fileName)!;}constctx:Contextcontext||getContext()ascommon.UIAbilityContext;constpreferenceUtil:PreferenceUtilnewPreferenceUtil(ctx,fileName);PreferenceUtil.preferenceRecord.set(fileName,preferenceUtil);returnpreferenceUtil;}publicgetPreferences():preferences.Preferences|null{returnthis.dataPreferences;}publicput(key:string,value:object|string|number|boolean):void{if(!this.dataPreferences){Logger.info(PreferenceUtil: dataPreferences is null);return;}try{this.dataPreferences.putSync(key,value);this.dataPreferences.flushSync();Logger.info(PreferenceUtil: put:${key});}catch(e){Logger.error(PreferenceUtil: put error:${JSON.stringify(e)});}}publicget(key:string,defaultValue:object|string|number|boolean):object|string|number|boolean{if(!this.dataPreferences){returndefaultValue;}try{returnthis.dataPreferences.getSync(key,defaultValue)asobject|string|number|boolean;}catch(e){Logger.error(PreferenceUtil: get error:${JSON.stringify(e)});returndefaultValue;}}publicdelete(key:string):void{if(!this.dataPreferences){return;}try{this.dataPreferences.deleteSync(key);this.dataPreferences.flushSync();Logger.info(PreferenceUtil: delete:${key});}catch(e){Logger.error(PreferenceUtil: delete error:${JSON.stringify(e)});}}}2.2 设计要点单例模式按文件名区分privatestaticpreferenceRecord:Mapstring,PreferenceUtilnewMap();publicstaticgetInstance(context?:Context,fileName:stringdefault):PreferenceUtil{if(PreferenceUtil.preferenceRecord.has(fileName)){returnPreferenceUtil.preferenceRecord.get(fileName)!;}// ...创建新实例}使用Map按fileName维护多个实例每个文件对应一个PreferenceUtil实例。缓存清理privateconstructor(context:Context,fileName:string){preferences.removePreferencesFromCacheSync(context,fileName);this.dataPreferencespreferences.getPreferencesSync(context,{name:fileName});}在创建实例前先从缓存中移除确保获取的是最新实例。这是处理开发热重载时缓存残留的关键。同步 APIthis.dataPreferences.putSync(key,value);this.dataPreferences.flushSync();使用同步 API 而非异步简化调用方代码。对于轻量级数据同步操作的性能影响可以忽略。容错处理publicput(key:string,value:object|string|number|boolean):void{if(!this.dataPreferences){Logger.info(PreferenceUtil: dataPreferences is null);return;}try{this.dataPreferences.putSync(key,value);this.dataPreferences.flushSync();}catch(e){Logger.error(PreferenceUtil: put error:${JSON.stringify(e)});}}所有操作都包含 try-catch确保存储异常不会导致应用崩溃。三、在 MainViewModel 中使用3.1 初始化// viewmodel/MainViewModel.etspublicasyncinit(context:Context):Promisevoid{this.prefUtilPreferenceUtil.getInstance(context,AppConstants.PREF_FILE);this.loadDays();}常量定义// common/Constants.etsexportclassAppConstants{publicstaticreadonlyPREF_FILE:stringimportant_days;publicstaticreadonlyPREF_KEY_DAYS:stringimportant_day_list;}3.2 加载数据privateloadDays():void{if(!this.prefUtil)return;constjsonStrthis.prefUtil.get(AppConstants.PREF_KEY_DAYS,[])asstring;try{constarr:string[]JSON.parse(jsonStr);this.dayListarr.map((json:string)ImportantDay.fromJSON(json)).filter((day:ImportantDay|null)day!null)asImportantDay[];}catch(e){Logger.error(MainViewModel: loadDays error:${JSON.stringify(e)});this.dayList[];}}3.3 保存数据privatesaveDays():void{if(!this.prefUtil)return;constarr:string[]this.dayList.map((day:ImportantDay)day.toJSON());this.prefUtil.put(AppConstants.PREF_KEY_DAYS,JSON.stringify(arr));}3.4 数据存储格式Preferences 中存储的数据结构文件: important_days 键: important_day_list 值: [{\id\:\1690000000000_3456\,\title\:\妈妈生日\,\date\:\2026-03-15\,\description\:\记得买蛋糕\,\colorIndex\:5,\countMode\:0,\repeatType\:1,\advanceDays\:3,\isPinned\:true,\createdAt\:1690000000000,\updatedAt\:1690000000000}]外层是一个 JSON 数组字符串每个元素是ImportantDay.toJSON()的结果。这种嵌套设计的原因Preferences 的putSync只支持基本类型string、number、boolean和 string将数组序列化为字符串存储可以一次性保存所有数据加载时一次性反序列化减少 IO 操作四、putSync 与 flushSync 的区别this.dataPreferences.putSync(key,value);// 写入内存缓存this.dataPreferences.flushSync();// 持久化到文件putSync将数据写入内存缓存速度极快flushSync将内存缓存的数据刷写到磁盘文件确保数据持久化两者必须配合使用。如果只调用putSync而不flushSync数据在应用关闭后会丢失。五、removePreferencesFromCacheSync 的作用preferences.removePreferencesFromCacheSync(context,fileName);这行代码在构造函数中调用用于从内存缓存中移除指定文件的 Preferences 实例。这在以下场景中很重要开发阶段热重载DevEco Studio 热重载时旧的 Preferences 实例可能还留在缓存中多实例场景确保每次getInstance获取的是最新状态数据同步防止缓存中的脏数据影响新实例六、存储方案扩展思考6.1 当前方案的局限全量保存每次修改都保存整个列表数据量大时可能有性能问题无索引查询某日的重要日需要遍历整个列表无事务多步操作不具备原子性6.2 如果使用 RDB如果未来数据量增长可以迁移到关系型数据库CREATETABLEimportant_days(idTEXTPRIMARYKEY,titleTEXTNOTNULL,dateTEXTNOTNULL,descriptionTEXT,color_indexINTEGERDEFAULT0,count_modeINTEGERDEFAULT0,repeat_typeINTEGERDEFAULT0,advance_daysINTEGERDEFAULT0,is_pinnedINTEGERDEFAULT0,created_atINTEGER,updated_atINTEGER);CREATEINDEXidx_dateONimportant_days(date);CREATEINDEXidx_pinnedONimportant_days(is_pinned);但当前 Preferences 方案对于这个应用规模完全够用简单可靠。七、小结本篇详细介绍了 ImportantDays 项目的数据持久化方案。PreferenceUtil 通过单例模式封装 Preferences API提供简洁的get/put/delete接口。MainViewModel 在每次 CRUD 操作后自动调用saveDays()持久化数据确保数据不丢失。

相关新闻

MT25QL512ABB8ESF-0SIT选型指南:工业级vs车规级NOR闪存对比与应用选型建议

MT25QL512ABB8ESF-0SIT选型指南:工业级vs车规级NOR闪存对比与应用选型建议

MT25QL512ABB8ESF-0SIT:美光工业级512Mb串行NOR闪存深度解析在工业控制、通信设备、医疗仪器以及物联网网关等对存储容量、数据可靠性和工作温度范围有综合要求的应用领域,系统设计需要在存储性能、引脚数量和长期供货保障之间进行权衡。与车规级版本相比…

2026/7/16 0:10:39阅读更多 →
鸿蒙 ArkTS 实战:Car Wash Weather Table 从出行记录到状态反馈完整解析

鸿蒙 ArkTS 实战:Car Wash Weather Table 从出行记录到状态反馈完整解析

鸿蒙 ArkTS 实战:Car Wash Weather Table 从出行记录到状态反馈完整解析 前言 Car Wash Weather Table 是一个面向 出行管理与通勤习惯 的鸿蒙 ArkTS 小应用。记录出行条目、站点信息和提醒备注,适合日常出行复盘。 本文基于 entry/src/main/ets/pages…

2026/7/16 0:10:39阅读更多 →
AD9215BRUZRL7-105是一款工业 10bit 流水线模数转换器

AD9215BRUZRL7-105是一款工业 10bit 流水线模数转换器

型号介绍AD9215BRUZRL7-105 是一款10 位单通道高速流水线模数转换器,它采用模拟单电源独立供电 数字驱动分离供电双电源架构,模拟电源 AVDD 额定 3V,允许工作区间 2.7V~3.3V;数字驱动电源 DRV 独立设计,支持 2.25V~3.…

2026/7/16 0:05:39阅读更多 →
多Agent协同系统设计:从单模型到可调度数字产线

多Agent协同系统设计:从单模型到可调度数字产线

1. 项目概述:这不是“调用API”,而是构建一个能自主协同的数字工人班组你有没有试过让一个AI助手帮你查资料、写周报、整理会议纪要——结果它卡在“把Excel里第三列数据按日期倒序排列”这一步,反复确认格式,最后还漏掉了两行&am…

2026/7/16 1:15:49阅读更多 →
LinkSwift:九大主流网盘直链下载助手完整使用指南

LinkSwift:九大主流网盘直链下载助手完整使用指南

LinkSwift:九大主流网盘直链下载助手完整使用指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘…

2026/7/16 1:15:49阅读更多 →
PDF对比神器diff-pdf:3分钟快速上手,工作效率翻倍提升

PDF对比神器diff-pdf:3分钟快速上手,工作效率翻倍提升

PDF对比神器diff-pdf:3分钟快速上手,工作效率翻倍提升 【免费下载链接】diff-pdf A simple tool for visually comparing two PDF files 项目地址: https://gitcode.com/gh_mirrors/di/diff-pdf PDF文档对比是许多办公场景中的刚需,但…

2026/7/16 1:15:49阅读更多 →
3步掌握TegraRcmGUI:新手也能上手的Switch破解完全指南

3步掌握TegraRcmGUI:新手也能上手的Switch破解完全指南

3步掌握TegraRcmGUI:新手也能上手的Switch破解完全指南 【免费下载链接】TegraRcmGUI C GUI for TegraRcmSmash (Fuse Gele exploit for Nintendo Switch) 项目地址: https://gitcode.com/gh_mirrors/te/TegraRcmGUI 你是否曾经面对复杂的命令行界面感到手足…

2026/7/16 1:15:49阅读更多 →
51单片机实现救护车双音警报声,含Keil工程文件与可烧录HEX

51单片机实现救护车双音警报声,含Keil工程文件与可烧录HEX

本文还有配套的精品资源,点击获取 简介:直接可用的51单片机蜂鸣器驱动项目,输出标准救护车交替高低频警报音(如‘呜—咦—呜—咦’循环),适配STC89C51、AT89C51等常见51内核芯片。核心代码用C语言编写&a…

2026/7/16 1:15:49阅读更多 →
从Copilot到自主Agent:ChatGPT写代码进阶路径图(含12个渐进式Prompt训练关卡+认证题库)

从Copilot到自主Agent:ChatGPT写代码进阶路径图(含12个渐进式Prompt训练关卡+认证题库)

更多请点击: https://codechina.net 第一章:从Copilot到自主Agent的演进本质与能力跃迁 从代码补全工具到具备目标分解、工具调用与自我反思能力的智能体,这一跃迁并非简单功能叠加,而是认知架构的根本性重构。Copilot 本质上是“…

2026/7/16 1:10:48阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/15 6:42:19阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/15 6:12:45阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/15 10:54:00阅读更多 →
A--10 Codex Review与GitHub PR工作流实战指南:从代码审查到安全合并

A--10 Codex Review与GitHub PR工作流实战指南:从代码审查到安全合并

摘要:本文系统讲解如何利用Codex App的Review功能与GitHub PR工作流,实现从代码修改到安全合并的完整流程。涵盖Review面板深度使用、/review命令实战、GitHub Connector配置、PR描述撰写技巧,以及常见问题排查方法。通过多个实战案例和流程图,帮助开发者建立高效的AI辅助代…

2026/7/16 0:00:38阅读更多 →
遗传算法解5皇后问题:从Hello World到工业优化的进化实验室

遗传算法解5皇后问题:从Hello World到工业优化的进化实验室

1. 项目概述:为什么用遗传算法解5皇后问题,而不是直接回溯?我带过十几届算法课,也给不少初创团队做过AI架构咨询。每次讲到组合优化问题,学生和工程师的第一反应永远是“写个回溯试试”。这没错——55棋盘上找所有合法…

2026/7/16 0:00:38阅读更多 →
5.1V稳压管输出为何只有4.7V?工作电流与负载影响分析

5.1V稳压管输出为何只有4.7V?工作电流与负载影响分析

前几天调试一个简单的电源模块,用到了5.1V稳压管。电路接好,上电测试,万用表一量——输出居然只有4.7V。第一反应是稳压管坏了,换了一个新的,结果还是4.7V。这让我想起很多初学者都会遇到的困惑:明明标称5.…

2026/7/16 0:00:38阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/15 15:50:47阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/15 8:52:38阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/15 14:06:23阅读更多 →