当前位置: 首页 > news >正文

HarmonyOS 6.1 全场景实战|《灵犀厨房》实战(二十八):【数据持久化】收藏与浏览历史——让数据在 App 重启后依然“活着”

HarmonyOS 6.1 全场景实战|《灵犀厨房》实战(二十八):【数据持久化】收藏与浏览历史——让数据在 App 重启后依然“活着”

摘要:收藏一道菜谱、回顾之前看过什么菜——这些功能在前 27 篇中只能活在内存里。App 重启后,所有收藏和历史全部消失。本篇利用已有的RelationalStoreHelper(完整 CRUD 封装),新增三张持久化表,让收藏和历史在 App 重启后依然存在。你还会学到:为什么收藏用主键约束而历史用追加写入?为什么浏览历史的写入失败不阻塞页面跳转?以及,如何用约 45 行代码完成从建表到 UI 联动的完整持久化闭环。


一、引言:内存的“失忆症”

一个有趣的测试:在第 27 篇的基础上,收藏一道“番茄牛腩煲”,然后关掉 App,重新打开。

收藏按钮恢复成了空心——App 完全忘记了刚才的操作。

这不是 Bug,这是内存的失忆症。前 27 篇中,所有用户数据——收藏的菜谱、浏览过的记录、个人偏好——都存储在@State@Local变量中。这些变量的生命周期与组件绑定,组件销毁时数据也随之消失。

数据类型存储位置生命周期App 重启后
推荐结果HomeViewModel.recommendedRecipes页面级❌ 消失
收藏状态RecipeDetailPage.heartLiked组件级❌ 消失
浏览记录无存储❌ 从未存在过

🎯本篇目标:利用已有的RelationalStoreHelper,新增收藏表、浏览历史表和社区分享表,配合 UI 层的两处微小改动,让数据在 App 重启后依然“活着”。核心代码仅约 45 行。


二、核心原理:关系型数据库的“记账本”模型

2.1 为什么是 SQLite 而非 Preferences?

HarmonyOS 提供了两种本地持久化方案:

方案数据结构查询能力适用场景
Preferences键值对仅 get(key)简单配置(头像路径、昵称)
RelationalStore(SQLite)表 + SQLSELECT/INSERT/DELETE/ORDER BY结构化数据(收藏、历史、订单)

收藏和历史属于后者——你需要按时间排序查询“最近浏览的 10 道菜”,需要判断“这道菜是否已收藏”。这些需求用键值对也能实现(把所有数据序列化为 JSON 存一个 key),但查询效率低、代码丑陋、容易出错。

关系型数据库就像一个记账本:每笔收藏是一行,每笔浏览也是一行。你可以随时翻阅(SELECT)、追加(INSERT)、划掉(DELETE),不需要关心这本账怎么保存——SQLite 替你管。

2.2 已有的基础设施

前 27 篇中,我们已经在RelationalStoreHelper中建立了完整的 CRUD 封装——initDatabase()executeSql()insert()方法。这些方法已用于用户登录注册的本地存储(local_users表)。本篇不新增任何数据库基础设施,只扩展现有实例。


三、表结构设计:每一列都有存在的理由

在已有的数据库LingxiKitchen.db中新增三张表:

-- 收藏表(recipe_id 为主键,保证同一菜谱只收藏一次)CREATETABLEIFNOTEXISTSfavorite_recipes(recipe_idINTEGERPRIMARYKEY,recipe_nameTEXTNOTNULL,saved_atINTEGERDEFAULT(strftime('%s','now')));-- 浏览历史表(每次浏览追加一条,不设主键约束)CREATETABLEIFNOTEXISTSrecipe_history(recipe_idINTEGERNOTNULL,recipe_nameTEXTNOTNULL,viewed_atINTEGERDEFAULT(strftime('%s','now')));-- 社区分享表(预留,为社区功能做准备)CREATETABLEIFNOTEXISTSshared_recipes(idINTEGERPRIMARYKEYAUTOINCREMENT,user_nameTEXTNOTNULL,recipe_nameTEXTNOTNULL,ingredientsTEXT,stepsTEXT,shared_atINTEGERDEFAULT(strftime('%s','now')));

建表语句在RelationalStoreHelper.createTables()中追加,使用CREATE TABLE IF NOT EXISTS保证幂等——重复调用不会出错。

设计考量

设计点选择理由
favorite_recipes主键recipe_id收藏是唯一性操作——同一菜谱只需一条记录,取消收藏时 DELETE,重新收藏时 INSERT
recipe_history主键无(追加写入)浏览是可重复操作——用户可能三天看五次“番茄牛腩煲”,完整时间线比最新记录更有分析价值
saved_at/viewed_at默认值strftime('%s','now')SQLite 内置时间函数,无需在 ArkTS 侧传入时间戳,减少代码量和时钟偏差风险
shared_recipes步骤字段TEXT(JSON 序列化)步骤是数组结构,SQLite 不直接支持数组类型,JSON 序列化是最简单的跨语言兼容方案

四、收藏逻辑:INSERT 与 DELETE 的一体两面

4.1 写入时机

RecipeDetailPage底部操作栏的收藏按钮中,在onClick中调用this.toggleFavorite()

.onClick(()=>{this.heartLiked=!this.heartLiked;this.heartScale=1.3;setTimeout(()=>{this.heartScale=1;},150);this.toggleFavorite();// ← 新增持久化,在动画播放的同时异步写入})

4.2 toggleFavorite 方法

privateasynctoggleFavorite():Promise<void>{try{if(this.heartLiked){awaitstoreHelper.insert('favorite_recipes',{recipe_id:this.recipe.id,recipe_name:this.recipe.name,saved_at:Date.now()});}else{awaitstoreHelper.executeSql('DELETE FROM favorite_recipes WHERE recipe_id = ?',[this.recipe.id.toString()]);}}catch(err){console.error('[RecipeDetail] 收藏持久化失败:',JSON.stringify(err));}}
SQLiteRelationalStoreHelper收藏按钮👤 用户SQLiteRelationalStoreHelper收藏按钮👤 用户点击收藏heartLiked = truescale 弹跳动画insert('favorite_recipes', {id, name})INSERT INTO favorite_recipesrowId再次点击(取消)executeSql('DELETE WHERE id=?')DELETE FROM favorite_recipesok

图一解读:收藏和取消收藏是同一操作的两个方向——用recipe_id作为主键,INSERT 和 DELETE 对称操作。数据库不关心用户是第一次收藏还是取消后重新收藏——它只执行 SQL,由 ArkTS 侧的heartLiked状态决定方向。

4.3 设计考量:为什么不阻塞动画?

toggleFavorite()是异步的,但onClick没有await它。这意味着动画先播(150ms 弹跳),数据库写入在后台并行进行。如果数据库写入失败(比如磁盘满),用户已经看到了动画反馈——这会不会不一致?

不会。收藏功能的核心价值是再次打开 App 时还能看到收藏,而不是“点击瞬间的数据一致性”。如果写入失败,下次打开 App 时收藏会丢失——这确实是个问题,但它发生的概率远低于用户因为等待 I/O 而感知到的卡顿。用户体验的优先级是:即时反馈 > 数据持久化 > 错误处理。前两者保证了“好用”,第三者保证了“不出大问题”。


五、浏览历史:追加写入,静默失败

5.1 写入时机

Index.etshandleRecipeTap方法开头新增写入:

privatehandleRecipeTap(recipe:Recipe):void{// ★ 写入浏览历史(失败不阻塞跳转)try{storeHelper.insert('recipe_history',{recipe_id:recipe.id,recipe_name:recipe.name,viewed_at:Date.now()});}catch(_err){}// 原有跳转逻辑(不受历史写入影响)this.getUIContext().getRouter().pushUrl({...});}

5.2 设计考量:为什么静默吞错误?

浏览历史不是关键路径。用户点击菜谱卡片时的核心诉求是看到菜谱详情,而不是“确保这次浏览被记录”。如果数据库写入失败(磁盘满、表损坏),阻塞跳转或弹出错误提示都会严重破坏体验。

失败

用户点击菜谱卡片

写入浏览历史

跳转详情页

静默忽略

用户看到菜谱详情 ✅

图二解读:浏览历史是一条分叉路——主路径(跳转)和副路径(写入)并行。副路径失败不影响主路径。这是“非关键路径静默失败”的设计模式——适用于所有“有更好、没有也行”的增值功能。

5.3 为什么是追加而非更新?

如果用户三天内看了五次“番茄牛腩煲”,你应该存五条记录还是一条记录?

策略存储方式能回答的问题
更新(UPDATE)一条记录,更新viewed_at“最近什么时候看过这道菜”
追加(INSERT)五条记录,各自有时间戳+ “看过多少次” + “什么时候最常看” + “看了之后收藏了吗”

追加的成本只是多占几行磁盘空间(每条约 100 字节),但换来了完整的行为时间线。后续可以扩展“最近浏览”列表、“猜你喜欢”推荐、“看了但没收藏”提醒等功能。追加不是冗余,是未来数据分析的基础设施。


六、代码交付清单

文件新增/修改行数说明
RelationalStoreHelper.ets修改+25createTables新增三张建表 SQL
RecipeDetailPage.ets修改+15收藏按钮加入toggleFavorite()调用
Index.ets修改+5handleRecipeTap新增浏览历史写入

七、设计决策

决策选择理由
收藏表主键recipe_id收藏是唯一性操作,同一菜谱只需一条记录
历史表写入策略追加(INSERT)而非更新保留完整行为时间线,为数据分析打基础
历史写入失败处理静默吞错误,不阻塞跳转浏览历史是增值功能,非关键路径
动画与持久化的顺序动画先播,持久化异步并行用户感知的延迟来自 I/O,动画填补了这段空白
不新建 DataSource 类直接复用storeHelper单例已有完整 CRUD,不引入额外抽象层

八、本阶段总结与下篇预告

本篇用约 45 行新增代码,让《灵犀厨房》的收藏和浏览历史从“内存失忆”变为“持久记忆”:

  • 三张新表favorite_recipes(收藏)、recipe_history(浏览历史)、shared_recipes(预留社区)
  • 收藏的 INSERT/DELETE 对称操作recipe_id主键让收藏和取消是同一操作的镜像
  • 浏览历史的追加写入:静默失败不阻塞跳转,完整时间线为未来数据分析打基础
  • 最小侵入:UI 层仅两处改动,数据库基础设施复用已有封装

现在重新打开 App,收藏依然在,浏览历史可追溯——App 开始有了“记忆”。

下篇预告:第 29 篇《个人中心:偏好持久化与推荐联动》。我们将把用户的口味偏好、忌口设置和健康档案持久化到本地数据库,并让推荐引擎在下次启动时自动读取这些偏好——真正做到“越用越懂你”。


📚 本系列持续更新中:下一篇将让推荐引擎与用户偏好联动,开启个性化推荐的正循环。

🔗专栏入口:[《HarmonyOS6.1全场景实战》合集]

📦 获取基线版本源码包:包括第1-15篇所有代码 + 架构文档 + Flask 后端

如果你觉得这篇文章对您有所帮助,麻烦您动动发财之手点赞 👍、收藏 ⭐ 和评论 💬。谢谢大家!!

http://www.jsqmd.com/news/958136/

相关文章:

  • 委托、多态、继承接口
  • 计算机毕业设计之C5.0决策树算法在学生成绩预测中应用
  • 实战应用:基于快马平台构建可部署的页面每日更新监控系统
  • 极域电子教室破解技术深度解析:从内核驱动到用户态对抗的完整方案
  • 终极免费FF14钓鱼计时器:渔人的直感完整使用教程
  • 航空搜救指挥痛点:三维电子沙盘如何破解复杂地形调度难题
  • Shiply 2026 自研升级API方案对比
  • 从零安装 Claude Code
  • 2026南宁家政公司十大排名,口碑第一名花落谁家?看完这篇不纠结 - 教育信息速递
  • 解锁上班新姿势[特殊字符]
  • Sora 2科学可视化不是“视频生成”,而是新一代计算叙事引擎(附IEEE VIS 2024预印本验证数据)
  • ai赋能内容平台:借助快马平台大模型为ao3镜像站实现智能标签与推荐
  • 无需下载matlab,用快马ai平台5分钟搭建在线矩阵计算与绘图原型
  • 学完吴恩达第一周,我整理了这份深度学习避坑指南:从数据、算力到算法选择
  • 【毕业设计】基于springboot+微信小程序的在线预约挂号系统基于微信小程序的智能在线预约挂号系统(源码+文档+远程调试,全bao定制等)
  • 【AI工具学习路径规划避坑白皮书】:基于237个真实学习案例的路径失效根因分析(附可执行诊断清单)
  • Gemini世界观构建:3天内完成从Prompt工程师到认知架构师的跃迁路径
  • 法律检索响应时间从15分钟压缩至8秒:北京知识产权法院AI辅助裁判系统内部操作手册首度流出
  • GEO优化公司推荐名单有哪些?GEO是什么公司?2026年6月国内GEO服务商TOP6综合测评 - 互联网科技品牌测评
  • SMUDebugTool:AMD Ryzen处理器深度调试与性能调优完整指南
  • 博主实测:为什么说德源 DYG5001 是 IGBT 封装中 3M 5413 的最强替身?
  • 如何快速解密科学文库PDF:3分钟完整破解指南
  • 六家 GEO 系统服务商实测横向测评,按企业发展周期筛选 TOP 推荐厂商
  • Anthropic千亿估值买不来未来:类脑智能正在逆袭
  • 农业AI入门:5分钟看懂植物叶片‘健康指纹’——高光谱反射曲线
  • 荣获参与奖哈哈
  • 新手零基础入门:借助快马ai生成你的第一个数据库交互网页应用
  • 为什么2026年将成为AI Agent元年
  • 2026宜昌防水补漏哪家好?住建实地测评权威榜单TOP5|卫生间免砸砖/阳台屋顶/厨卫漏水维修(6月宜昌专项调研) - 苏易修缮
  • 3步掌握APK安装器:Windows上运行安卓应用的终极指南