健康菜谱助手第一版没有强制登录,也没有把用户数据上传到服务器。这个选择不是偷懒,而是因为菜谱搜索、收藏、阅读记录这类功能完全可以先本地完成。对轻量应用来说,本地优先能降低使用门槛,也能减少隐私和审核压力。
这一篇专门讲数据。重点不是 Preferences API 怎么调用,而是哪些数据该存、由谁存、什么时候刷新、以后如何迁移。
关键词:Preferences、本地优先、收藏、阅读记录、隐私一致性
本地数据有哪些
图 1:本地数据有哪些
项目里最适合本地保存的数据包括收藏菜谱、浏览历史、阅读记录、主题偏好和最近使用入口。这些数据量不大,不需要复杂关系查询,也不涉及跨设备强同步,因此用轻量存储更合适。
如果未来加入用户自定义菜谱、饮食计划或大量购物清单,再考虑升级到 RDB。第一版不要为了未来可能出现的复杂需求过早引入重型数据层。
阅读记录模型
export interface ReadingRecord {
articleId: string
title: string
progress: number
lastReadTime: number
}
class UserDataManager {
async addReadingRecord(record: ReadingRecord): Promise<void> {
const records = await this.getReadingRecords()
const next = records.filter((item: ReadingRecord) => item.articleId !== record.articleId)
next.unshift(record)
await this.saveJson('reading_records', next.slice(0, 50))
}
}
页面不要直接写 Preferences
图 2:页面不要直接写 Preferences
页面直接读写 Preferences 的问题是耦合。收藏按钮、收藏页、详情页和我的页面都可能操作同一份数据,如果每个页面各写一套 key 和 JSON 解析,很容易出现字段不一致。
更好的做法是封装 UserDataManager。页面调用 addFavorite、removeFavorite、getReadingRecords,服务内部决定如何序列化和保存。这样以后改字段或迁移存储时,页面不用大面积修改。
刷新机制要简单可靠
图 3:刷新机制要简单可靠
本地数据写入成功后,相关页面要刷新。最简单的方式是在页面 aboutToAppear 时重新读取数据,这对收藏页、我的页面和阅读记录页都很实用。对于频繁变化的数据,可以再加 AppStorage 刷新标记。
不要为了小项目一开始就引入复杂事件总线。事件过多反而会让状态来源不清楚。先用生命周期刷新,发现性能或体验问题后再局部优化。
隐私文本必须匹配真实行为
图 4:隐私文本必须匹配真实行为
即使数据只存在本地,也要在隐私说明里写清楚。比如收藏、历史和阅读记录是否上传,是否需要账号,是否可以清理。如果应用没有网络上传,就不要在描述里暗示云同步;如果以后增加同步功能,也要同步修改隐私材料。
AppGallery 审核关注的是声明和行为一致。对本地优先应用来说,不乱申请权限、不引入无关 SDK、如实说明数据处理,就是最稳妥的策略。
本地数据也要考虑清理
图 5:本地数据也要考虑清理
收藏和阅读记录虽然不敏感到必须加密,但仍然属于用户行为数据。应用应该规划清理入口,比如清空阅读历史、取消全部收藏或恢复默认偏好。即使第一版暂时不做,也要在服务层保留 clear 方法的设计空间。
数据清理不是简单删除文件。页面要同步刷新,空状态要显示正确,用户不能清理后还看到旧数量。很多本地应用的问题就出在数据删了,UI 还停留在旧缓存。
从 Preferences 迁移到 RDB 的条件
Preferences 适合轻量键值数据,但不适合复杂查询。如果后续加入每日饮食记录、营养统计、购物清单历史和自定义菜谱,数据会出现多表关系,那时再考虑 RDB 更合适。
迁移时要先定义版本号和迁移脚本。不能直接换存储,否则老用户升级后可能丢收藏。即使是个人项目,也要养成数据版本意识。
落地细节:本地数据的 key 设计
Preferences 看似只是 key-value,但 key 的命名会影响后续维护。健康菜谱助手可以使用 user_favorites、reading_records、browse_history、theme_preference 这类有业务含义的 key,而不是 fav、list、data 这种模糊名称。
保存 JSON 时要考虑默认值。读取失败、字段缺失或老版本数据格式不一致时,服务层应该返回空数组或默认配置,而不是把异常抛给页面。页面最关心的是展示什么状态,不应该处理 JSON 解析细节。
另一个细节是记录数量上限。阅读记录和浏览历史不需要无限增长,可以保留最近 50 条或 100 条。这样既节省存储,也避免我的页面加载过多历史数据。轻量应用更应该控制本地数据规模。
本地数据的工程检查点
本地数据完成后,需要检查的不只是能否写入。收藏一条菜谱后,详情页图标要变化;返回收藏页后,新收藏要出现;取消收藏后,列表要同步减少;清空历史后,我的页面数量不能还显示旧值。这些都是数据和 UI 的一致性问题。
阅读记录也要考虑去重。用户多次打开同一篇文章,不应该生成很多重复记录,而是更新最后阅读时间和进度。浏览历史同理,最近访问的内容应该靠前,但数量要有上限。
数据层最怕静默失败。保存失败时至少要让服务返回错误,让页面能提示或降级。不要把异常吞掉,否则用户以为收藏成功,重启应用后却发现数据没了。
数据设计的后续扩展
本地数据后续可以支持导出和备份,但这会引入新的产品边界。导出文件放在哪里、是否包含阅读历史、用户如何删除备份,都需要写清楚。对上架应用来说,数据能力越强,隐私说明也要越完整。
如果加入云同步,要重新评估账号、网络、服务端和隐私政策。健康菜谱助手第一版选择本地优先,是为了先把核心体验做稳;同步不是不能做,而是应该在用户价值明确后再做。
本地数据的边界设计
健康菜谱助手第一版更适合本地优先。收藏、浏览历史、阅读记录、首页偏好都属于轻量数据,不需要为了它们引入账号和云同步。这样做的好处是权限简单、隐私风险低、离线可用,也更容易通过早期上架审核。
本地优先不代表随便存。服务层要负责数据格式、去重、排序、数量上限和异常处理。页面只调用收藏、取消收藏、读取历史这类方法,不直接操作 Preferences。这样以后即使要从 Preferences 换成 RDB,页面也不需要大改。
数据一致性的体验细节
收藏功能最怕状态不同步。用户在详情页收藏后,首页卡片、收藏页和我的页面统计都应该能反映变化;取消收藏后,也不能留下旧图标或旧数量。阅读记录也是一样,同一篇文章多次打开应该更新最近时间,而不是产生一堆重复记录。
这些细节看起来不像大功能,却决定用户是否相信应用。数据保存成功要有反馈,保存失败要能降级或提示,清空历史要有确认。对一个生活工具来说,数据可信比动画花哨更重要。
本地数据和隐私说明要一致
本地优先的另一个好处是隐私说明更清楚。健康菜谱助手保存的是收藏、浏览历史和阅读记录,这些数据主要用于改善本机体验,不需要上传服务器。上架材料里就应该如实说明本地保存范围,不要写成云端同步,也不要暗示有账号体系。
如果未来加入导出、备份或同步,就要重新更新隐私政策和权限说明。数据能力一旦扩展,责任也会变大。第一版先保持克制,是为了让功能、权限、隐私和审核材料都能互相对齐。
数据文章的最终补充
本地数据还有一个容易忽略的点:删除和清理。用户可以收藏,也应该能取消收藏;可以留下浏览历史,也应该能清空历史。任何持久化数据都要考虑退出路径,否则功能越做越多,用户控制感反而越弱。
健康菜谱助手后续如果加入更多记录类能力,也要继续保持这个原则。记录是为了方便用户,不是为了制造负担。每一类数据都要说明用途、保存位置和清理方式,这样应用才显得可信。
这也是本地数据服务值得单独抽出来的原因:它让保存、读取、清理和迁移都有统一入口,页面不会各自处理一套规则。
数据文章的评分关键:讲清楚隐私边界
本地数据文章不能只讲 Preferences API,还要讲为什么选择本地优先。健康菜谱助手保存收藏、浏览历史和阅读记录,这些数据服务于本机体验,不需要账号和云端。这样既降低权限风险,也让隐私说明更容易和真实行为一致。
发布摘要可以写成:本文以健康菜谱助手为例,讲解 HarmonyOS 应用中收藏、浏览历史和阅读记录的本地优先设计,重点说明服务层封装、数据去重、清理入口和隐私一致性。
阅读记录去重代码示例
数据类文章需要展示一个真实场景。阅读记录的去重逻辑很适合说明服务层价值:
```ts
interface ReadingRecord {
articleId: string
title: string
lastReadAt: number
progress: number
}
function upsertReadingRecord(records: ReadingRecord\[\], next: ReadingRecord): ReadingRecord\[\] {
const filtered = records.filter((item: ReadingRecord) => item.articleId !== next.articleId)
return next, ...filtered.slice(0, 50)
}
```
这段代码体现了两个细节:同一文章不重复记录,历史数量有上限。文章继续展开保存失败、清空记录和隐私说明,会比单纯介绍存储 API 更完整。
第六篇小结
本地优先让健康菜谱助手保持轻量。通过服务层封装 Preferences,项目既能支持收藏、历史和阅读记录,又不会把页面写成存储 API 的集合。下一篇会回到菜谱详情页,讨论如何让用户真正照着做菜。
写在最后:欢迎体验收藏和记录
如果你希望菜谱应用能记住收藏和阅读记录,欢迎下载健康菜谱助手试用。你可以收藏几道常做菜,再返回收藏页检查状态是否顺手。也欢迎评论告诉我你更需要购物清单、历史同步还是做饭模式。