ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

山海万灵 HarmonyOS 文化知识实战(11):护照收藏与进度统计

山海万灵 HarmonyOS 文化知识实战(11):护照收藏与进度统计 一、把探索行为收敛成一份可恢复的进度文化知识应用中的“收藏”并不只是给卡片切换一个图标。山海万灵把一次神兽发现同时映射到图鉴收录、地域探索比例、护照印章和下次进入时的区域位置。如果这些结果由各页面各自保存重复发现、切换区域和重启恢复很容易出现不一致。工程把可变的探索数据定义为ShanhaiLocalProgress版本号、已发现神兽 ID、已选地域、已选展厅与更新时间放在同一份记录中。图鉴资料、地域资料和展厅资料仍然属于启动数据不与用户进度混存。这样重置进度只影响本机探索记录不会删除知识内容或远端资料。export interface ShanhaiLocalProgress { schemaVersion: number; discoveredIds: string[]; selectedRegionId: string; selectedHallId: string; updatedAt: number; } export function createEmptyShanhaiLocalProgress(): ShanhaiLocalProgress { return { schemaVersion: SHANHAI_LOCAL_PROGRESS_SCHEMA_VERSION, discoveredIds: [], selectedRegionId: , selectedHallId: , updatedAt: 0 }; }二、Preferences 只保存原子字段领域状态保持完整形状仓储以shanhai_local_progress作为 Preferences 文件名分别写入 schema、发现 ID 串、地域 ID、展厅 ID 和更新时间。ID 在写入前去重并以分隔符序列化读取失败、类型不符或存储不可用时返回空进度而不是把异常值直接交给页面。async save(progress: ShanhaiLocalProgress): Promisevoid { const store: preferences.Preferences | null await this.getStore(); if (store null) { return; } await store.put(KEY_SCHEMA_VERSION, SHANHAI_LOCAL_PROGRESS_SCHEMA_VERSION); await store.put(KEY_DISCOVERED_IDS, this.serializeIds(progress.discoveredIds)); await store.put(KEY_SELECTED_REGION_ID, progress.selectedRegionId); await store.put(KEY_SELECTED_HALL_ID, progress.selectedHallId); await store.put(KEY_UPDATED_AT, progress.updatedAt); await store.flush(); }这里有两个边界需要保留。第一flush()使一次用户动作对应一次明确的落盘完成点第二仓储层吞掉的是持久化异常页面仍可继续浏览当前内容并由同步状态提示后续动作。页面不需要知道键名或序列化格式。三、发现神兽时一次性更新图鉴、护照和位置ShanhaiAppViewModel.discoverBeast是状态更新入口。它先判断目标是否存在再判断是否已经发现新发现的 ID 只追加到复制后的数组。随后把神兽所属地域和展厅写为当前探索位置持久化后用启动数据与本地进度重新生成聚合结果。const alreadyDiscovered: boolean this.localProgress.discoveredIds.indexOf(beast.id) 0; const discoveredIds: string[] this.localProgress.discoveredIds.slice(); if (!alreadyDiscovered) { discoveredIds.push(beast.id); } this.localProgress this.normalizeLocalProgress(bootstrap, { schemaVersion: SHANHAI_LOCAL_PROGRESS_SCHEMA_VERSION, discoveredIds: discoveredIds, selectedRegionId: beast.regionId, selectedHallId: beast.hallId, updatedAt: Date.now() }); await this.persistLocalProgress(); const mergedBootstrap: ShanhaiBootstrap this.applyLocalProgress(bootstrap, this.localProgress);这种顺序避免了“页面先改了计数、存储失败后无法恢复”的双源状态。重复发现不会再次增加记录但仍会返回已有发现的提示无效 ID 则保持原进度不变。四、进度和护照印章都由发现记录推导地域进度不单独保存百分比。视图模型遍历地域的beastIds统计已经发现的数量再计算百分比和“已收录 x/y”状态。护照印章也遵循同一条规则一个地域的全部神兽都在discoveredIds中时该地域才进入passportRegionIds。private derivePassportRegionIds(regions: RegionItem[], discoveredIds: string[]): string[] { return regions .filter((region: RegionItem) region.beastIds.length 0 region.beastIds.every((beastId: string) discoveredIds.indexOf(beastId) 0)) .map((region: RegionItem) region.id); } private applyDiscoveryProgressToRegions(regions: RegionItem[], discoveredIds: string[]): RegionItem[] { return regions.map((region: RegionItem): RegionItem { const discoveredCount: number region.beastIds .filter((beastId: string) discoveredIds.indexOf(beastId) 0).length; const progress: number region.beastIds.length 0 ? 0 : Math.round(discoveredCount * 100 / region.beastIds.length); return { ...region, progress: progress, status: 已收录 discoveredCount / region.beastIds.length }; }); }从同一个事实源派生统计能保证档案页的“已发现”和“护照印章”与地图卡片的区域进度始终对应。地域没有目录时进度固定为 0避免除零和虚假的完成印章。五、页面只消费结果并保留可见的失败出口本次验证安装了当前构建的山海万灵包在图鉴中完成九尾狐的发现动作后回到档案页。页面回读显示“已发现 3 种神兽”和“护照印章 1 枚”说明发现记录已经驱动统计和印章结果而不是只改变详情页上的局部控件。随后结束应用进程并重新启动同一包档案页仍保留 3 条发现记录、1 枚护照印章以及最近探索地域“青丘”。这只验证本机 Preferences 的恢复链路本文不把它扩展为云端同步、跨设备迁移或网络请求成功的结论。验收时还应把“发现”和“完成地域”分开观察前者直接增加 discoveredIds后者要等一个地域目录中的全部神兽都已收录才产生护照印章。这样既能避免单次发现被误记为地域完成也让 UI 上的两个数字能追溯到不同的派生规则。若存储层暂时不可用应用仍可保留本次会话中的知识浏览和状态展示下一次启动按空进度恢复不把未落盘的数据伪装成持久结果。页面层调用syncDiscovery后回写discoveredIds、passportRegionIds、地域和展厅数据。新出现的印章会被标记为高亮目标本地 fallback 状态会转换为页面可读的同步提示。失败时不伪造成功结果而是保留当前内容并显示重试路径。档案页把发现数和护照印章数作为明确的Prop传入统计面板统计组件不读取 Preferences。这样窄屏、宽屏和主题切换只影响排版不会改变进度计算。场景进度写入页面结果首次发现神兽追加 ID、更新地域与展厅位置图鉴、地域进度和护照候选一起重算重复发现保留原 ID 集合不重复计数继续展示关联探索提示存储读取异常使用空进度知识资料仍可浏览进度从初始状态开始本地进度重置清空进度仓储图鉴资料、个人档案和远端数据保持不变六、验收要覆盖恢复、重复动作和局部重置这条链路的验收不应只看一个数字。应先在图鉴中完成一次发现确认档案统计、地域进度和护照印章基于同一条记录更新再重启应用检查发现 ID、当前地域和展厅位置是否恢复。随后重复触发同一神兽确认计数不增加最后打开本地进度重置确认框检查取消不会变更记录确认重置后只回到探索初始状态。对于网络数据源不可用的场景继续检查本地 fallback 是否保留可浏览内容并让同步横幅提供重试入口。这样持久化失败、无效目标和重复动作都有明确的状态边界而不是由页面临时补丁掩盖。七、总结山海万灵用一份版本化的本地进度记录承载发现、地域和展厅选择Preferences 负责持久化原子字段视图模型负责归一化、去重和派生统计ArkUI 页面只展示已经聚合的结果。收藏、护照印章与探索进度因此共享同一条数据链路重置也能准确限定在本机探索状态内。
返回列表