ArkTS 进阶之道(28):PersistentStorage 持久化状态边界——为啥应用重启后状态仍存在跨启动状态根因 ArkTS 进阶之道28PersistentStorage 持久化状态边界——为啥应用重启后状态仍存在跨启动状态根因本文是「ArkTS 进阶之道」系列第 28 篇续「ArkUI 状态联动」深水区。上篇讲状态管理装饰器全景边界V1/V2 双轨根因。本文讲持久化状态边界PersistentStorage 持久化 AppStorage 键到磁盘——根因在应用重启后状态仍存在跨启动状态。能力系列篇 28 讲过 PersistentStorage 怎么用本文讲为哈 PersistentStorage 持久化状态合法 AppStorage 应用级状态页面卸载状态仍存在不跨启动——根因在持久化状态存储槽。一、开篇PersistentStorage 不是应用级 AppStorage是持久化到磁盘的跨启动状态你写 React 时持久化状态是「localStorage 魔法」localStorage JSON 序列化到磁盘// React 持久化状态localStorage 魔法JSON 序列化到磁盘 function usePersistedState(key: string, defaultValue: any) { const [value, setValue] useState(() { const stored localStorage.getItem(key) // 从磁盘读 return stored ? JSON.parse(stored) : defaultValue }) useEffect(() { localStorage.setItem(key, JSON.stringify(value)) }, [key, value]) // 改写磁盘 return [value, setValue] } // React 持久化状态localStorage 魔法JSON 序列化到磁盘应用重启仍存在你写鸿蒙 ArkTS 时PersistentStorage持久化 AppStorage 键到磁盘——应用重启后状态仍存在// ArkTS PersistentStorage 持久化 AppStorage 键到磁盘 AppStorage.setOrCreate(persistCount, 0) PersistentStorage.persistProp(persistCount, 0) // ✅ 持久化 AppStorage 键到磁盘 Entry Component struct Index { StorageLink(persistCount) persistCount: number 0 // ✅ StorageLink 双向绑定持久化键 build() { Button(persistCount${this.persistCount}) .onClick(() { this.persistCount }) // ✅ 改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 } } // PersistentStorage 持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态localStorage 魔法 vs 持久化状态存储槽的区别React 把持久化状态当 localStorage 魔法JSON 序列化到磁盘ArkTS 把 PersistentStorage 当「持久化状态存储槽」持久化 AppStorage 键到磁盘。根因不是 localStorage 魔法是持久化状态存储槽——PersistentStorage 持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态。二、根因PersistentStorage 的持久化状态存储槽机制鸿蒙 ArkUI 的 PersistentStorage 是持久化状态存储槽绑定——持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态来自三重绑定机制。机制 1PersistentStorage 持久化 AppStorage 键到磁盘——不是应用级内存PersistentStorage 荬饰器持久化 AppStorage 键到磁盘——应用重启后状态仍存在跨启动状态// ✅ 初始化 PersistentStorage持久化 AppStorage 键到磁盘 AppStorage.setOrCreate(persistCount, 0) PersistentStorage.persistProp(persistCount, 0) // ✅ 持久化 AppStorage 键到磁盘 Entry Component struct Index { StorageLink(persistCount) persistCount: number 0 // ✅ StorageLink 双向绑定持久化键 build() { Column() { Text(persistCount ${this.persistCount}) Button(改 persistCount) .onClick(() { this.persistCount }) // ✅ 改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 } } } // PersistentStorage 持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态不丢持久化 AppStorage 键到磁盘PersistentStoragepersistCount持久化 AppStorage 键到磁盘——应用重启后persistCount仍存在跨启动状态不丢。根因不是应用级内存是持久化状态存储槽——PersistentStorage 持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态。机制 2StorageLink 双向绑定持久化键——改互同步持久化到磁盘StorageLink 荬饰器双向绑定持久化键——改 StorageLink → AppStorage 同步 → PersistentStorage 持久化到磁盘Entry Component struct Index { StorageLink(persistCount) persistCount: number 0 // ✅ StorageLink 双向绑定持久化键 build() { Column() { Text(persistCount ${this.persistCount}) Button(改 persistCount) .onClick(() { this.persistCount }) // ✅ 改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 } } } // StorageLink 双向绑定持久化键改 → AppStorage 同步 → PersistentStorage 持久化到磁盘跨启动StorageLink 双向绑定持久化键StorageLinkpersistCount荬饰器双向绑定持久化键——改persistCount→ AppStorage 同步 → PersistentStorage 持久化到磁盘跨启动。根因不是只 AppStorage 同步是持久化到磁盘——StorageLink 双向绑定持久化键改 → AppStorage 同步 → PersistentStorage 持久化到磁盘。机制 3AppStorage.set 改 → PersistentStorage 同步持久化——不用 StorageLink 也能持久化AppStorage.set改 AppStorage 键→ PersistentStorage 同步持久化到磁盘不用 StorageLink 也能持久化Entry Component struct Index { StorageLink(persistCount) persistCount: number 0 // ✅ StorageLink 双向绑定持久化键 build() { Column() { Text(persistCount ${this.persistCount}) Button(直接改 AppStorage.set(persistCount, 999)) .onClick(() { AppStorage.set(persistCount, 999) // ✅ AppStorage 改 → PersistentStorage 同步持久化到磁盘 }) } } } // AppStorage.set 改 → PersistentStorage 同步持久化不用 StorageLink 也能持久化到磁盘AppStorage.set 改 → PersistentStorage 同步持久化AppStorage.setpersistCount改 AppStorage 键 → PersistentStorage 同步持久化到磁盘不用 StorageLink 也能持久化。根因不是必须用 StorageLink 是 AppStorage.set 直接改——AppStorage.set 改 → PersistentStorage 同步持久化到磁盘。机制 4PersistentStorage vs AppStorage 边界——跨启动 vs 应用级PersistentStorage持久化状态应用重启后状态仍存在跨启动AppStorage应用级状态所有页面共享页面卸载状态仍存在不跨启动——根因都是状态存储但绑的机制不同// ✅ PersistentStorage 路径持久化状态应用重启后状态仍存在跨启动 AppStorage.setOrCreate(persistCount, 0) PersistentStorage.persistProp(persistCount, 0) // ✅ 持久化到磁盘 Entry Component struct PersistPage { StorageLink(persistCount) persistCount: number 0 // ✅ 持久化键跨启动 build() { Button(持久化 ${this.persistCount}).onClick(() { this.persistCount }) } } // ✅ PersistentStorage 持久化状态应用重启后状态仍存在跨启动持久化到磁盘 // ⚠ AppStorage 路径应用级状态所有页面共享页面卸载状态仍存在不跨启动 AppStorage.setOrCreate(appCount, 0) Entry Component struct AppPage { StorageLink(appCount) appCount: number 0 // ⚠ 应用级键不跨启动应用重启销毁 build() { Button(应用级 ${this.appCount}).onClick(() { this.appCount }) } } // ⚠ AppStorage 应用级状态所有页面共享页面卸载状态仍存在不跨启动内存应用重启销毁PersistentStorage vs AppStorage 边界PersistentStorage 路径——持久化状态应用重启后状态仍存在跨启动持久化到磁盘。AppStorage 路径——应用级状态所有页面共享页面卸载状态仍存在不跨启动内存应用重启销毁。根因都是状态存储但绑的机制不同——PersistentStorage 持久化状态存储槽跨启动AppStorage 应用级状态存储槽不跨启动。三、真机配图PersistentStorage 持久化状态边界——跨启动状态初始态persistCount0 葝色、持久化状态边界初始态齐点调两按钮后persistCount999 葝色被 AppStorage.set 直接改 999 覆盖、PersistentStorage 持久化状态边界证据齐对比证据点改 persistCount 后 AppStorage 同步 PersistentStorage 持久化到磁盘StorageLink 双向同步点直接改 AppStorage.set(“persistCount”, 999) 后 persistCount999 被 AppStorage.set 直接改 999 覆盖 PersistentStorage 同步持久化到磁盘。PersistentStorage 持久化状态——持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态StorageLink 双向绑定持久化键AppStorage.set 改 → PersistentStorage 同步持久化。四、真解法PersistentStorage 持久化状态的三个场景场景 1PersistentStorage 持久化用户偏好90% 场景首选跨启动状态用持久化AppStorage.setOrCreate(themeColor, #007DFF) PersistentStorage.persistProp(themeColor, #007DFF) // ✅ 持久化用户偏好到磁盘 Entry Component struct Index { StorageLink(themeColor) themeColor: string #007DFF // ✅ StorageLink 双向绑定持久化键 build() { Column() { Text(themeColor ${this.themeColor}).fontColor(this.themeColor) Button(改 themeColor红色) .onClick(() { this.themeColor #FF4D4F }) // ✅ 改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 } } }为哈能跑PersistentStorage 持久化用户偏好——持久化状态存储槽PersistentStoragethemeColor持久化 AppStorage 键到磁盘StorageLink 双向绑定持久化键改themeColor→ AppStorage 同步 → PersistentStorage 持久化到磁盘跨启动。首选这个90% 的场景跨启动状态用 PersistentStorage 持久化状态存储槽就够。要写「跨启动状态用户偏好等」时用这个——不用 AppStorage 应用级不跨启动PersistentStorage 持久化到磁盘跨启动。场景 2PersistentStorage 持久化登录状态跨启动状态应用重启仍登录AppStorage.setOrCreate(isLoggedIn, false) PersistentStorage.persistProp(isLoggedIn, false) // ✅ 持久化登录状态到磁盘 Entry Component struct Index { StorageLink(isLoggedIn) isLoggedIn: boolean false // ✅ StorageLink 双向绑定持久化键 build() { Column() { Text(isLoggedIn ${this.isLoggedIn}) Button(登录) .onClick(() { this.isLoggedIn true }) // ✅ 改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 Button(退出) .onClick(() { this.isLoggedIn false }) // ✅ 改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 } } } // PersistentStorage 持久化登录状态应用重启仍登录跨启动状态持久化到磁盘为哈能跑PersistentStorage 持久化登录状态——持久化状态存储槽PersistentStorageisLoggedIn持久化 AppStorage 键到磁盘StorageLink 双向绑定持久化键改isLoggedIn→ AppStorage 同步 → PersistentStorage 持久化到磁盘跨启动。要写「跨启动状态登录状态等」时用这个——不用 AppStorage 应用级不跨启动PersistentStorage 持久化到磁盘跨启动应用重启仍登录。场景 3PersistentStorage vs AppStorage vs LocalStorage 作用域边界跨启动 vs 应用级 vs 页面级// ✅ PersistentStorage 跨启动应用重启后状态仍存在持久化到磁盘跨启动状态用这个 AppStorage.setOrCreate(persistState, 0) PersistentStorage.persistProp(persistState, 0) // ✅ 跨启动持久化到磁盘 Entry Component struct PersistComp { StorageLink(persistState) persistState: number 0 // ✅ 跨启动应用重启仍存在 build() { Button(跨启动 ${this.persistState}).onClick(() { this.persistState }) } } // ✅ AppStorage 应用级所有页面共享页面卸载状态仍存在不跨启动内存应用级状态用这个 AppStorage.setOrCreate(appState, 0) Entry Component struct AppComp { StorageLink(appState) appState: number 0 // ✅ 应用级所有页面共享不跨启动 build() { Button(应用级 ${this.appState}).onClick(() { this.appState }) } } // ✅ LocalStorage 页面级同页面多组件共享页面卸载就销毁内存页面级状态用这个 interface LocalState { pageState: number } const localStorage new LocalStorage({ pageState: 0 } as LocalState) Component struct PageComp { LocalStorageLink(pageState) pageState: number 0 // ✅ 页面级同页面共享页面卸载就销毁 build() { Button(页面级 ${this.pageState}).onClick(() { this.pageState }) } } // PersistentStorage vs AppStorage vs LocalStorage 作用域边界 // 跨启动用 PersistentStorage持久化到磁盘应用级用 AppStorage内存不跨启动页面级用 LocalStorage内存页面卸载销毁为哈能跑PersistentStorage vs AppStorage vs LocalStorage 作用域边界——跨启动状态用 PersistentStorage持久化到磁盘应用重启仍存在应用级状态用 AppStorage内存不跨启动所有页面共享页面级状态用 LocalStorage内存页面卸载销毁同页面多组件共享。要写「选对状态存储槽作用域跨启动 vs 应用级 vs 页面级等」时用这个——跨启动用 PersistentStorage应用级用 AppStorage页面级用 LocalStorage。五、一句话哲学PersistentStorage 不是应用级 AppStorage是持久化到磁盘的跨启动状态存储槽。ArkUI 的 PersistentStorage 荬饰器持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态。根因不是应用级 AppStorage 是持久化状态存储槽——PersistentStorage 持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态 StorageLink 双向绑定持久化键改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 AppStorage.set 改 → PersistentStorage 同步持久化不用 StorageLink 也能持久化到磁盘 PersistentStorage vs AppStorage 边界跨启动 vs 应用级。对比 React 持久化状态 localStorage 魔法JSON 序列化到磁盘ArkTS PersistentStorage 持久化状态存储槽跨启动状态。状态联动深水区串讲Watch 绑 State 变触发副作用回调槽篇 68 Link $ 语法双向绑定跨组件同步篇 69 Provide/Consume 跨层级传递槽祖辈后辈同步篇 70 Observed/ObjectLink 嵌套对象观测槽子属性改刷 UI篇 71 AppStorage 应用级状态存储槽所有页面共享篇 72 LocalStorage 页面级状态存储槽同页面多组件共享篇 73 StorageLink/StorageProp 应用级状态绑定边界双向 vs 只读篇 74 LocalStorageLink/LocalStorageProp 页面级状态绑定边界双向 vs 只读篇 75 状态管理装饰器全景边界 V1/V2 双轨篇 76 PersistentStorage 持久化状态存储槽跨启动状态篇 77应用重启后状态仍存在——续「ArkUI 状态联动」深水区讲状态联动深水区Watch 副作用回调槽边界 Link $ 语法双向绑定边界 Provide/Consume 跨层级传递槽边界 Observed/ObjectLink 嵌套对象观测槽边界 AppStorage 应用级状态存储槽边界 LocalStorage 页面级状态存储槽边界 StorageLink/StorageProp 应用级状态绑定边界 LocalStorageLink/LocalStorageProp 页面级状态绑定边界 状态管理装饰器全景边界 V1/V2 双轨 PersistentStorage 持久化状态存储槽边界。系列预告下篇篇 78讲 Environment 环境变量状态边界环境变量注入根因续「ArkUI 状态联动」深水区。五阶段哲学体系类型哲学50-52→ 作用域哲学53-55→ 状态哲学56-59→ 渎染哲学60-62→ 组件设计63-67→ 状态联动深水区68讲清 ArkTS/ArkUI 进阶哲学。能力系列回链能力系列篇本文进阶点篇 28 PersistentStorage 用法PersistentStorage 持久化状态存储槽边界根因跨启动状态持久化到磁盘篇 23 AppStorage 用法应用级状态存储槽边界所有页面共享页面卸载状态仍存在不跨启动篇 59 Watch 用法状态联动深水区Watch 副作用回调槽 vs onClick 直接调副作用边界真机 demo 完整代码// 篇 77 demoPersistentStorage 持久化状态边界 // PersistentStorage 持久化 AppStorage 键到磁盘——应用重启后状态仍存在跨启动状态 AppStorage.setOrCreate(persistCount, 0) PersistentStorage.persistProp(persistCount, 0) // ✅ 持久化 AppStorage 键到磁盘API 21 用 persistProp Entry Component struct Index { StorageLink(persistCount) persistCount: number 0 // ✅ StorageLink 双向绑定持久化键 State log: string (未操作) build() { Column({ space: 12 }) { Text(篇 77 配图PersistentStorage 持久化状态边界) .fontSize(16).fontWeight(FontWeight.Bold).margin({ top: 16, bottom: 4 }) Text(PersistentStorage 持久化 AppStorage 键到磁盘——应用重启后状态仍存在跨启动状态) .fontSize(10).fontColor(#888).margin({ bottom: 8 }) Column({ space: 6 }) { Text(持久化状态PersistentStorage) .fontSize(12).fontColor(#2563eb).fontWeight(FontWeight.Bold) Text(persistCount ${this.persistCount}) .fontSize(15).fontWeight(FontWeight.Bold).fontColor(#2563eb) Text(应用重启后仍存在——跨启动状态) .fontSize(10).fontColor(#888) } .width(92%).padding(10).backgroundColor(#e0f0ff).borderRadius(8) Button(改 persistCount持久化到磁盘) .width(92%).height(40).fontSize(12) .onClick(() { this.persistCount // ✅ 改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 this.log 改 persistCount${this.persistCount}持久化到磁盘重启仍存在 }) Button(直接改 AppStorage.set(persistCount, 999)) .width(92%).height(40).fontSize(12) .onClick(() { AppStorage.set(persistCount, 999) // ✅ AppStorage 改 → PersistentStorage 同步持久化 this.log 直接改 AppStorage.set persistCount999持久化同步 }) Text(日志${this.log}).fontSize(10).fontColor(#333).margin({ top: 4 }) Text(对比AppStorage 应用级状态页面卸载状态仍存在vs PersistentStorage 持久化状态应用重启仍存在) .fontSize(10).fontColor(#ff6600).margin({ top: 8 }) } .width(100%).height(100%).alignItems(HorizontalAlign.Center) } }写鸿蒙 ArkUI 记住PersistentStorage 不是应用级 AppStorage 是持久化到磁盘的跨启动状态存储槽——PersistentStorage 荬饰器持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态。根因不是应用级 AppStorage 是持久化状态存储槽——PersistentStorage 持久化 AppStorage 键到磁盘应用重启后状态仍存在跨启动状态 StorageLink 双向绑定持久化键改 → AppStorage 同步 → PersistentStorage 持久化到磁盘 AppStorage.set 改 → PersistentStorage 同步持久化不用 StorageLink 也能持久化到磁盘 PersistentStorage vs AppStorage 边界跨启动 vs 应用级。PersistentStorage 持久化用户偏好用持久化状态存储槽首选90% 场景PersistentStorage 持久化登录状态用持久化状态存储槽跨启动应用重启仍登录PersistentStorage vs AppStorage vs LocalStorage 作用域边界选对存储槽跨启动用 PersistentStorage 持久化到磁盘应用级用 AppStorage 内存不跨启动页面级用 LocalStorage 内存页面卸载销毁。持久化到磁盘跨启动状态应用重启仍存在是 ArkUI 状态联动深水区核心