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

第93篇 | HarmonyOS 生命周期刷新:返回页面后数据为什么要重新读

第93篇 | HarmonyOS 生命周期刷新:返回页面后数据为什么要重新读

页面生命周期是训练营后期必须补上的工程底座。用户从系统相册选择照片、从分享面板返回、从视频任务页回来、从保险箱解锁再返回,页面如果仍然使用旧状态,就会出现“明明导入了却看不到”“任务生成了但状态没变”的体验问题。

这一篇重点看aboutToAppearonPageShowaboutToDisappear和数据刷新函数之间的关系。生命周期刷新不是重复调用接口,而是在正确的时机恢复监听、刷新记录、释放资源。

本篇目标

  • 理解首次进入、再次显示、离开页面三个阶段各自做什么。
  • 确认返回页面后会重新读取相册记录和视频任务状态。
  • 看懂退出页面时为什么要释放分享监听、握姿监听和播放器。
  • 建立生命周期回归表,覆盖导入、分享、解锁、视频任务返回。

对应源码位置

  • superImage/entry/src/main/ets/pages/Index.ets

首次进入和再次显示都要补数据

aboutToAppear负责首次进入页面时启动地图、加载相册、恢复视频状态、注册分享监听。onPageShow则处理应用重新回到前台后的刷新。两者职责接近,但触发时机不同。

如果只在首次进入读取数据,用户从系统选择器导入照片后返回,页面可能还是旧记录;如果只在 onPageShow 读取,首次打开又容易漏初始化。

生命周期刷新把页面进入、返回和离开整理成清楚闭环

aboutToAppear(): void { this.applyActiveSystemBarStyle(); this.prepareScenicAgentEntry(); void this.loadGalleryRecords(); void this.loadVideoManagerRecords(); void this.loadGalleryCloudSyncSession(); void this.registerNearbyShareListeners(); if (this.activeTab === 'map') { void this.refreshCurrentLocation(true); void this.startHoldingHandAwareness(); } else if (this.activeTab === 'camera') { this.scheduleCameraCapabilityPrepare(); } void this.loadVolcengineConfig(); this.backSurfaceController.setCreateHandler((surfaceId: string) => { this.backSurfaceId = surfaceId; this.scheduleCameraCapabilityPrepare(80); }); this.backSurfaceController.setDestroyHandler(() => { this.backSurfaceId = ''; void this.teardownDualPreview(!this.shouldPreserveSequentialCaptureContext()); }); this.frontSurfaceController.setCreateHandler((surfaceId: string) => { this.frontSurfaceId = surfaceId; void this.ensureCameraPreview(); }); this.frontSurfaceController.setDestroyHandler(() => { this.frontSurfaceId = ''; void this.teardownDualPreview(!this.shouldPreserveSequentialCaptureContext()); }); this.mapCallback = async (err, controller) => { if (err) { const message = err.message && err.message.length > 0 ? err.message : JSON.stringify(err); this.mapReady = false; this.mapErrorText = `记忆地图初始化失败 ${err.code ?? -1}:${message}`; console.error(`[superImage][map] init failed code=${err.code ?? -1} message=${message}`); return; } this.mapController = controller; this.mapEventManager = this.mapController.getEventManager(); this.mapReady = true; this.mapErrorText = ''; this.showMapControllerIfActive(); this.bindMarkerClickEvent(); await this.primeMapCameraAtUserLocation(); await this.syncMapMarkers(); if (this.hasLiveLocation()) { this.focusMapAtCoordinate(this.currentLatitude, this.currentLongitude, false); } else { void this.refreshCurrentLocation(true); } }; } onPageShow(): void { this.applyActiveSystemBarStyle(); this.prepareScenicAgentEntry(); void this.loadGalleryRecords(); void this.loadVideoManagerRecords(); void this.loadGalleryCloudSyncSession(); void this.registerNearbyShareListeners(); if (this.activeTab === 'map') { void this.refreshCurrentLocation(true); void this.startHoldingHandAwareness(); } else if (this.activeTab === 'camera') { this.scheduleCameraCapabilityPrepare(); } void this.loadVolcengineConfig(); this.showMapControllerIfActive(); } onPageHide(): void { this.clearCameraCapabilityPrepareTimer(); this.unregisterNearbyShareListeners(); this.stopGalleryAntiPeepProtection(); this.hideMapController(); this.normalMovieVideoController.pause(); this.normalMoviePreviewPlaying = false; void this.releaseNormalMoviePreviewMusic(); this.hideCameraCapturePreview(); this.stopLocationAwareness(); this.stopHoldingHandAwareness(); void this.teardownDualPreview(); } aboutToDisappear(): void {

读取记录后要同步多个页面状态

读取相册记录不是简单赋值。项目会在applyGalleryRecords后更新保险箱选中项、同步地图标记、修正详情页可见性。因为同一份记录同时支撑相册、地图、保险箱和回忆通知。

这也是为什么生命周期刷新不能只刷新当前 tab。用户在相册导入照片,地图页和保险箱页也可能依赖这份记录。

相册记录刷新会影响多个页面,不能只更新当前可见卡片

const vaultRecords = records.filter((record: GalleryMoment) => record.visibility === 'private'); this.gallerySelectedId = publicRecords.some((record: GalleryMoment) => record.id === this.gallerySelectedId) ? this.gallerySelectedId : (publicRecords.length > 0 ? publicRecords[0].id : ''); this.vaultSelectedId = vaultRecords.some((record: GalleryMoment) => record.id === this.vaultSelectedId) ? this.vaultSelectedId : (vaultRecords.length > 0 ? vaultRecords[0].id : ''); this.syncGalleryFocus(records); this.syncGalleryGroupSelection(); } private async applyGalleryRecords(records: Array<GalleryMoment>): Promise<void> { const publicRecords = records.filter((record: GalleryMoment) => record.visibility !== 'private'); this.galleryRecords = records; this.capturePairCount = records.length; this.syncRecordSelections(records); this.syncSelectedMapMemory(false); await this.syncMapMarkers(); this.updateAwarenessRecommendation(false);

数据变更后要刷新媒体状态

导入、移动保险箱、恢复公开相册、视频任务完成,这些操作都会改变记录集合。项目用refreshGalleryMediaStateAfterMutation把保存、选中项、媒体 tab 和同步状态串起来,避免某个页面遗留旧选择。

这个函数的价值在于“变更后统一收口”。如果每个按钮各自改一部分状态,后续很容易出现选中 id 不存在、详情页还打开、视频页仍显示旧记录。

数据变更后统一刷新选中项和页面状态,减少散落状态

private async refreshGalleryMediaStateAfterMutation( preferredRecordId: string, scope: 'gallery' | 'vault' ): Promise<void> { const savedRecords = await GalleryRecordService.loadRecords(this.getAbilityContext()); await this.applyGalleryRecords(savedRecords); const preferredRecord = preferredRecordId.length > 0 ? savedRecords.find((record: GalleryMoment) => record.id === preferredRecordId) : undefined; if (preferredRecord) { if (preferredRecord.visibility === 'private' || scope === 'vault') { this.vaultSelectedId = preferredRecord.id; } else { this.gallerySelectedId = preferredRecord.id; this.selectedGalleryGroupKey = this.buildGalleryRecordGroupKey(preferredRecord); this.galleryUserNoteDraft = this.getRecordUserNote(preferredRecord); } } if (this.galleryViewMode === 'detail' && !this.getFeaturedGalleryRecord()) { this.galleryViewMode = 'album'; this.stopGalleryAntiPeepProtection(); } if (this.vaultDetailVisible && !this.getFeaturedVaultRecord()) { this.vaultDetailVisible = false; } this.capturePairCount = savedRecords.length; } private async appendGalleryRecord(record: GalleryMoment): Promise<void> { this.logCaptureTrace( 'append-gallery-record-start', `recordId=${record.id} pairIndex=${record.pairIndex} backPath=${record.backPath} frontPath=${record.frontPath}` ); const readyRecord = record.aiStatus === 'ready' ? record : GalleryRecordService.applyLocalInsight(record); const nextRecords = [readyRecord, ...this.galleryRecords.filter((item: GalleryMoment) => item.id !== readyRecord.id)]; this.galleryRecords = nextRecords; this.syncRecordSelections(nextRecords); this.gallerySelectedId = readyRecord.id; this.selectedGalleryGroupKey = this.buildGalleryRecordGroupKey(readyRecord); this.galleryUserNoteDraft = this.getRecordUserNote(readyRecord); this.showCameraCapturePreview(readyRecord); this.syncSelectedMapMemory(true); this.capturePairCount = nextRecords.length; this.galleryNoticeText = this.hasGalleryFocus() ? this.getGalleryScopeDescription() : '' await this.syncMapMarkers(); this.updateAwarenessRecommendation(false); await this.persistGalleryRecords(nextRecords); this.gallerySelectedId = readyRecord.id; this.selectedGalleryGroupKey = this.buildGalleryRecordGroupKey(readyRecord); this.logCaptureTrace(

离开页面时要释放能力

aboutToDisappear不是可有可无。分享监听、握姿感知、视频播放器、相机资源都可能在页面不可见后继续占用资源;离开页面时释放,能减少后台异常和重复回调。

发布前回归要包含“进入页面 -> 打开系统相册/分享/认证 -> 返回 -> 切后台 -> 再回来”的路径。只测首次启动,很难覆盖生命周期问题。

离开页面和返回路径都要处理当前 tab 的临时状态

生命周期代码的验收标准不是“函数被调用”,而是用户返回后看到的数据是新的,离开后资源不再继续工作。

工程验收表

检查项通过标准
首次进入相册、地图、视频任务、分享监听都能初始化。
返回刷新从系统选择器、分享面板、认证页返回后数据不旧。
变更收口导入、移动、恢复、删除后选中项仍有效。
离开释放离开页面后监听和播放器不会继续占资源。

真机复测口令

从相册页拉起系统选择器导入照片,返回应用后观察列表是否刷新;从视频任务页提交任务后切到后台,再回到前台观察状态是否恢复;从地图页离开再回来,确认监听和地图状态不会重复初始化。

生命周期问题最适合按“进入 -> 外部动作 -> 返回 -> 再离开”的路径复测。每条路径都要记录触发的是aboutToAppearonPageShow还是aboutToDisappear,避免把首次初始化和前台恢复混成同一件事。

今日练习

  1. onPageShow中打印刷新日志,确认返回前台时确实触发。
  2. 导入一张照片后立即返回相册,检查记录数量是否变化。
  3. 离开地图页再进入,确认监听没有重复注册。
http://www.jsqmd.com/news/1006240/

相关文章:

  • 2026视频号视频怎么保存到相册?视频号视频保存到相册方法全攻略
  • 第1节:初识C语言
  • 个人档案是什么终于搞懂了,毕业再也不怕处理档案了! - 慧办好
  • 装修不踩雷!汉中装修设计品牌挑选思路与经验分享 - 国麟测评
  • 个人档案查询网上查询如何办理?河南线上查档保姆级教程! - 慧办好
  • 【深度解析】轩麟电永磁吸盘:核心原理与工业应用 - 速递信息
  • 三步告别游戏黑屏:Borderless Gaming让你的游戏窗口无缝切换
  • Windows上运行安卓应用的终极方案:APK安装器完全指南
  • Java MD5加密与Swagger实战教程
  • 北京大兴区黄金回收店评测:三条核心指标筛选,爱回收12家门店全地址 - 新闻快传
  • 嵌入式SRAM深度解析:MC68377操作模式、内存映射与工程实践
  • 北京朝阳区黄金回收店推荐:爱回收24家门店全地址,选店三条标准说清楚 - 新闻快传
  • 终极指南:掌握AlienFX Tools,释放Alienware灯光与风扇的全部潜能
  • 昆山汽车座垫脚垫定制怎么选?车饰源(车舒源)品质突围 - 百航
  • 2026年国内GEO服务商怎么选?这份指南帮你避开80%的踩坑风险 - 速递信息
  • 2023-2025年江苏省省级企业技术中心名单深度分析报告
  • 使用语义分割经典模型 HRNet 训练道路分割模型并测试使用——从高分辨率特征到工程落地实践
  • MC68349中断与总线异常处理:从硬件原理到嵌入式系统调试实战
  • 2026年中国GEO服务商综合实力权威测评排行榜,全栈自研标杆的泓动数据领跑GEO优化行业3.0时代 - 互联网科技品牌测评
  • 给芯片做‘体检’:一文搞懂DFT扫描链的插入与测试流程(以Tessent为例)
  • 2026照片去水印免费软件App有哪些?手机免费去水印软件App推荐与安全无广告排行
  • 3个关键步骤让Citra模拟器在PC上流畅运行3DS游戏
  • 货损降至0%!无锡靠谱物流公司推荐案例解析 - 速递信息
  • 2026在线音频转文字怎么操作?免费工具+详细上手教程
  • 告别抠图!用Mask R-CNN实战分割商品图,Python+PyTorch保姆级教程
  • Vue-Fabric-Editor深度解析:插件化架构如何重构Web图片编辑体验
  • 车仕宝汽车服务:上海汽车补胎换胎专业施工透明无套路 - 百航
  • CI/CD前世今生(持续集成、持续交付、持续部署、Jenkins、Github Actions)
  • Poppins字体完整指南:多语言排版终极解决方案
  • 2026 武汉表包金钻回收门道解析 耀辉黄金奢侈品回收本地标杆实力全览 - 奢侈品回收