: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 狀態聯動深水區核心