纹渊 HarmonyOS 7 工程实战(09):图库、收藏与最近浏览的数据恢复

发布时间:2026/7/20 13:55:28

纹渊 HarmonyOS 7 工程实战(09):图库、收藏与最近浏览的数据恢复 一、图库状态为什么只保存 ID纹样图库中的收藏和最近浏览都属于“小数据、高频读写”的状态卡片内容来自内置数据集用户真正改变的只是卡片顺序和是否收藏。如果把整张卡片对象写入持久化存储后续字段调整、图片资源替换或文案更新都会留下旧副本只保存number[]类型的纹样 ID页面恢复时再从当前数据集中解析状态更轻也不会冻结业务数据。状态写入时机存储内容页面恢复方式收藏长按卡片切换收藏去重后的纹样 ID 列表按 ID 映射为当前版本卡片最近浏览打开纹样详情最新访问优先的 ID 列表保持访问顺序并过滤失效 ID页面字段页面创建或重新进入不单独持久化并行读取后一次性更新可观测状态这里的关键边界是Preferences 保存用户选择纹样数据集保存业务事实。两者通过稳定 ID 关联而不是复制整份对象。二、把读写失败收口成确定结果Preferences 获取失败、键不存在、JSON 损坏都不应阻断图库页面。底层读写函数把异常收口读取失败返回调用方给出的默认值写入时执行put后立即flush页面层只接收确定的数据不需要重复编写异常分支。async function readString( context: common.Context, key: string, fallback: string ): Promisestring { const store await getPrefs(context) if (store null) { return fallback } try { return await store.get(key, fallback) as string } catch { return fallback } } async function writeValue( context: common.Context, key: string, value: preferences.ValueType ): Promisevoid { const store await getPrefs(context) if (store null) { return } try { await store.put(key, value) await store.flush() } catch { // 保留当前页面状态下一次操作仍可重试 } }这种处理没有把“写入成功”和“页面可用”绑死。持久化暂时不可用时当前会话仍然可以显示操作结果重新进入页面后读取逻辑再回退为空数组避免白屏或未捕获异常。三、收藏切换与最近浏览不是同一种规则收藏是集合语义已有 ID 再次触发就移除不存在则插到列表头部。最近浏览是有序队列语义每次访问都先删除旧位置再把 ID 放到首位并限制为 20 条。两者都保存 ID 数组但更新规则不能共用一个笼统的“追加”函数。export async function loadFavoriteIds( context: common.Context ): Promisenumber[] { const raw await readString(context, KEY_FAVORITES, []) try { const parsed JSON.parse(raw) as number[] return Array.isArray(parsed) ? parsed : [] } catch { return [] } } export async function saveFavoriteIds( context: common.Context, ids: number[] ): Promisevoid { await writeValue(context, KEY_FAVORITES, JSON.stringify(ids)) } export async function toggleFavorite( context: common.Context, id: number ): Promisenumber[] { const ids await loadFavoriteIds(context) const index ids.indexOf(id) if (index 0) { ids.splice(index, 1) } else { ids.unshift(id) } await saveFavoriteIds(context, ids) return ids }export async function pushRecentPattern( context: common.Context, id: number ): Promisevoid { const raw await readString(context, KEY_RECENT, []) let ids: number[] [] try { const parsed JSON.parse(raw) as number[] ids Array.isArray(parsed) ? parsed : [] } catch { ids [] } const next ids.filter((item: number) item ! id) next.unshift(id) await writeValue(context, KEY_RECENT, JSON.stringify(next.slice(0, 20))) }操作收藏列表结果最近浏览结果首次操作 ID 8[8, ...][8, ...]再次操作 ID 8从收藏中移除ID 8 移到首位连续访问同一项不适用始终只保留一条数据持续增长由用户主动管理自动截断为最近 20 条四、恢复链路要在页面渲染前完成页面恢复时收藏和最近浏览可以并行读取两项都完成后再结束恢复阶段。渲染前还要把 ID 映射到当前纹样数据集找不到的 ID 直接过滤。这样即使新版本删除了某个纹样旧存储也只会少显示一张卡片不会产生空对象访问。private reloadFavRecent(): Promisevoid { if (this.uiCtx null) { return Promise.resolve() } return Promise.all([ loadFavoriteIds(this.uiCtx).then((ids: number[]) { this.favoriteIds ids }), loadRecentIds(this.uiCtx).then((ids: number[]) { this.recentIds ids }) ]).then(() {}) } private patternsByIds(ids: number[]): Pattern[] { const result: Pattern[] [] ids.forEach((id: number) { const pattern getPatternById(id) if (pattern ! undefined) { result.push(pattern) } }) return result }打开详情时先导航再异步写入最近浏览写入完成后刷新recentIds。用户返回收藏页时能看到最新顺序而路由跳转不会被磁盘写入阻塞。收藏长按则等待服务返回新的 ID 列表后直接赋值ArkUI 根据可观测字段重建对应卡片区域。五、空状态和损坏数据也属于正常输入可靠的数据恢复不能只验证“有数据”的情况。空数组要显示明确的引导文案存储值不是数组时回退为空旧 ID 已从数据集移除时过滤连续打开同一项时保持唯一写入失败时当前页面仍保持可操作。异常输入处理策略用户看到的结果Preferences 中没有对应键使用字符串[]作为默认值收藏与最近浏览显示空状态JSON 解析失败捕获异常并返回空数组页面正常进入不展示损坏记录读取结果不是数组类型检查后回退为空数组不把错误结构传给ForEach纹样 ID 已失效映射阶段跳过未找到项其余卡片按原顺序展示同一纹样重复浏览先过滤旧 ID 再前插最近列表无重复项记录超过 20 条写入前截断列表体积保持稳定Preferences 的基础用法和数据持久化约束可参考华为开发者文档Preferences 数据持久化。实际业务仍要在它之上补齐 JSON 校验、顺序规则和页面恢复策略。六、验证恢复闭环首次安装后进入收藏页确认收藏和最近浏览分别显示空状态不出现空白卡片。在图库长按两张纹样卡片进入收藏页核对两张卡片及其顺序再次长按其中一张确认它被移除。依次打开三张纹样详情再重复打开第一张确认第一张移动到最近浏览首位且没有重复。结束应用进程后重新进入确认收藏集合与最近浏览顺序恢复。将存储内容模拟为非法 JSON 或非数组结构确认页面回退为空状态并且仍可继续收藏。模拟数据集删除一个旧 ID确认该卡片被过滤其余卡片顺序不变。七、总结图库状态恢复的重点不是把数组写入 Preferences而是把集合规则、队列规则、异常兜底和页面刷新连成一条确定链路。收藏使用切换语义最近浏览使用去重前插与长度上限页面只保存可观测 ID 列表并在渲染前解析为当前版本的数据对象。这样既能保留用户习惯也能承受数据升级、损坏记录和持久化失败。

相关新闻