鸿蒙 ArkTS 状态管理:三类状态的生命周期与失效边界
背景
做鸿蒙端侧应用时,最容易被低估的不是 ArkUI 的声明式语法,而是状态的生命周期。一个页面上看起来正常的列表,切到后台再回来就丢了勾选;一个表单填到一半,横竖屏切换后输入框清空。这些问题在模拟器上很难复现,只有在真机反复切前后台才暴露出来。
我做了什么
我用 ArkTS 写了一个「喝水记录」小应用,作为验证状态管理方案的最小实验田。它只有三个页面:首页进度环、记录列表、设置。目标很朴素——把 UI 状态、持久化状态、跨页共享状态三类彻底分开,看看到底哪一层在什么时机失效。
具体做法是:进度数值用 @State 只在本页存活;当天累计杯数用 AppStorage 做跨页共享;历史记录写进 Preferences,只在 onPageShow 时读一次、在真正落库后写一次。
关键机制
三类状态失效的时机完全不同,这是整件事最关键的一点:
- @State 随组件销毁而销毁。页面被
router.replaceUrl换掉再回来,它就是初始值,和「数据丢了」完全两回事。 - AppStorage 活在应用进程里,切前后台不受影响,但进程被回收就全没。它是「会话级」而不是「持久级」。
- Preferences 是唯一能跨进程存活的,但它是异步 API,且在
aboutToAppear里读往往还没回调完,UI 已经渲染了第一帧空数据。
所以那次「勾选丢了」的真实原因,是勾选态存在 @State 里而列表数据从 Preferences 重读过一遍,两者不同步——不是我一开始怀疑的持久化失败。
踩的坑
第一个坑:把 Preferences 的读取放在 aboutToAppear 里 await,结果首帧永远是空的。改成先渲染骨架、回调到达后再 @State 赋值刷新,闪一下的问题才消失。
第二个坑:@StorageLink 和 @StorageProp 的区别。前者双向、后者单向,我在一个只读的统计组件上用了 @StorageLink,结果那个组件里的一次误赋值把全局计数改了,排查花了很久。
第三个坑:进度环用 Canvas 画,尺寸跟着容器走,横屏后容器变了但 Canvas 没重绘,环就糊在角落。必须在 onAreaChange 里显式重算半径。
结论
把「谁该活多久」先想清楚,比事后到处加刷新可靠得多。我的经验是:能只活一页的就别上升到 AppStorage,能只在会话里共享的就别写盘,写盘的一定要做「先渲染后填充」。这三条定下来之后,后面新增的页面几乎没有再出现状态错乱。也建议把这三类状态在代码里用注释显式标出来,团队协作时比口头约定有用。
- 点赞
- 收藏
- 关注作者
评论(0)