
前言在 ArkUI 状态管理体系中数据存储被分为三个层级AppStorage应用级内存存储、PersistentStorage持久化键值存储、LocalStorage页面级内存存储。这三个层级各有不同的作用范围、生命周期和适用场景合理选择它们直接决定了应用的数据一致性、持久化能力和性能表现。本文将以开源鸿蒙笔友通信应用 xiexin 的DataStore.ets为蓝本详细剖析这三个存储层级的语义、差异以及它们在实际开发中的选型策略。提示本文假设你已经了解 ArkUI 状态管理的基本概念。如果还不熟悉建议先阅读前十三篇文章。一、三级存储总览1.1 三个层级的核心差异维度AppStoragePersistentStorageLocalStorage存储位置应用进程内存磁盘文件页面实例内存生命周期应用进程存在持久化到存储页面实例存在作用范围整个应用整个应用单个页面及子组件数据持久化否进程重启丢失是重启后恢复否页面销毁丢失访问方式StorageLink/StoragePropPersistentStorage.persistPropLocalStorage实例典型用途用户信息、列表数据用户偏好、登录态页面内临时状态1.2 xiexin 当前的使用情况xiexin 当前只使用了AppStorage没有使用 PersistentStorage 和 LocalStorage// DataStore.ets — 仅使用 AppStorage static initializeData(): void { AppStorage.setOrCreatePenPal[](penPals, penPals); AppStorage.setOrCreateLetter[](letters, letters); AppStorage.setOrCreateUserProfile(userProfile, profile); AppStorage.setOrCreateWriteStats(writeStats, stats); AppStorage.setOrCreateInviteRecord[](invites, []); AppStorage.setOrCreateboolean(hasSeenSplash, false); AppStorage.setOrCreatenumber(currentTab, 0); }这种设计的局限是应用重启后所有数据丢失。xiexin 当前作为“纯演示“应用可以接受但如果要落地为真实产品必须引入 PersistentStorage 实现数据持久化。二、AppStorage应用级内存存储2.1 AppStorage 的核心特性AppStorage是应用启动时创建的单例对象在应用进程运行期间一直存在。// 写入 AppStorage.setOrCreate(key, value); // 不覆盖已有值 AppStorage.set(key, value); // 强制覆盖 // 读取 const value AppStorage.get(key); // 不存在返回 undefined // 删除 AppStorage.delete(key); // 清空 AppStorage.clear();2.2 AppStorage 的装饰器绑定// StorageLink双向绑定组件修改 → AppStorage 更新 StorageLink(penPals) penPals: PenPal[] []; // StorageProp单向绑定AppStorage → 组件组件修改不更新 AppStorage StorageProp(penPals) penPals: PenPal[] [];2.3 AppStorage 的最佳实践适用场景不适用场景页面间共享的数据页面内临时状态从网络加载的列表数据用户偏好设置需要跨组件同步的数据磁盘 IO 密集型数据数据量大但不频繁修改需要持久化的数据三、PersistentStorage持久化键值存储3.1 PersistentStorage 的核心特性PersistentStorage提供持久化键值存储能力数据会写入磁盘应用重启后可以恢复。import { PersistentStorage } from kit.ArkUI; // 持久化一个 key并关联到 AppStorage PersistentStorage.persistProp(hasSeenSplash, false); // 删除持久化 key PersistentStorage.deleteProp(hasSeenSplash); // 持久化后通过 AppStorage 访问 const hasSeenSplash AppStorage.getboolean(hasSeenSplash) ?? false;3.2 PersistentStorage 的工作原理graph LR subgraph 内存 AS[AppStorage: hasSeenSplash true] end subgraph 磁盘 PS[PersistentStorage] end AS --|持久化同步| PS当PersistentStorage.persistProp(hasSeenSplash, false)被调用后键hasSeenSplash被注册到 AppStorage如果磁盘中已有hasSeenSplash的值从磁盘恢复如果磁盘中还没有用默认值false初始化后续AppStorage.set(hasSeenSplash, true)会同步写入磁盘应用重启后AppStorage.get(hasSeenSplash)返回true3.3 PersistentStorage 的约束约束说明值类型限制仅支持number、string、boolean、Object及其数组不支持 class 实例不能持久化Observed类的实例最大 key 数量无明确限制但建议不超过 100 个同步写入持久化操作是同步的3.4 在 xiexin 中引入 PersistentStorage// 改造后的 DataStore.ets import { PersistentStorage } from kit.ArkUI; export class DataStore { static initializeData(): void { // 持久化的状态用 persistProp 注册 PersistentStorage.persistProp(hasSeenSplash, false); PersistentStorage.persistProp(currentTab, 0); PersistentStorage.persistProp(userProfile, JSON.stringify(new UserProfile())); // 非持久化的状态用 setOrCreate const penPals: PenPal[] DataStore.createMockPenPals(); AppStorage.setOrCreatePenPal[](penPals, penPals); const letters: Letter[] DataStore.createMockLetters(); AppStorage.setOrCreateLetter[](letters, letters); } }四、LocalStorage页面级内存存储4.1 LocalStorage 的核心特性LocalStorage是页面级的内存存储绑定到页面实例的生命周期。// 创建 LocalStorage 实例 const pageStorage new LocalStorage(); pageStorage.setOrCreate(pageTitle, 写信); // 在 Entry 组件中绑定 Entry(pageStorage) Component struct ComposePage { LocalStorageProp(pageTitle) pageTitle: string ; LocalStorageLink(draft) draft: string ; }4.2 LocalStorage 的装饰器绑定// LocalStorageProp单向绑定 LocalStorageProp(pageTitle) pageTitle: string ; // LocalStorageLink双向绑定 LocalStorageLink(draft) draft: string ;4.3 LocalStorage 的典型应用场景// 场景页面内多 Tab 共享状态 const pageStorage new LocalStorage(); pageStorage.setOrCreate(currentTab, 0); pageStorage.setOrCreate(searchQuery, ); // 页面组件 Entry(pageStorage) Component struct ComplexPage { LocalStorageProp(currentTab) currentTab: number 0; build() { Tabs({ index: this.currentTab }) { TabContent() { SearchTab() } TabContent() { BrowseTab() } } } } // 子组件共享同一个 LocalStorage Component struct SearchTab { LocalStorageLink(searchQuery) searchQuery: string ; build() { TextInput({ text: this.searchQuery }) .onChange((value: string) { this.searchQuery value; // 子组件修改父组件和其他子组件自动同步 }) } }五、三级存储选型决策树数据是否需要持久化 ├── 是 → PersistentStorage │ └── 数据是否需要跨页面共享 │ ├── 是 → 使用 persistProp 注册到 AppStorage │ └── 否 → 使用 AppStorage非持久化或持久化到文件 └── 否 → 数据是否需要跨页面共享 ├── 是 → AppStorage └── 否 → 数据是否需要跨子组件共享 ├── 是 → LocalStorage └── 否 → State 组件私有状态六、xiexin 的存储层改造建议6.1 当前状态分析xiexin 当前的数据存储需求数据当前存储是否需要持久化是否跨页面共享建议方案penPals笔友列表AppStorage是是PersistentStorage序列化letters信件列表AppStorage是是PersistentStorage序列化userProfile用户信息AppStorage是是PersistentStorageJSONwriteStats统计数据AppStorage是是从 letters 实时计算invites邀请记录AppStorage是是PersistentStorage序列化hasSeenSplash引导状态AppStorage是否PersistentStoragecurrentTabTab 索引AppStorage否是AppStorage6.2 改造后的 DataStoreimport { PersistentStorage } from kit.ArkUI; export class DataStore { static initializeData(): void { // 1. 持久化的原子状态 PersistentStorage.persistProp(hasSeenSplash, false); PersistentStorage.persistProp(currentTab, 0); // 2. 持久化的复杂对象序列化存储 const savedProfile AppStorage.getstring(saved_profile); if (!savedProfile) { const profile DataStore.createMockProfile(); PersistentStorage.persistProp(saved_profile, JSON.stringify(profile)); } // 反序列化回 AppStorage const profileStr AppStorage.getstring(saved_profile) ?? {}; const profile: UserProfile JSON.parse(profileStr); AppStorage.setOrCreateUserProfile(userProfile, profile); // 3. 非持久化的运行时数据 const penPals: PenPal[] DataStore.createMockPenPals(); AppStorage.setOrCreatePenPal[](penPals, penPals); const letters: Letter[] DataStore.createMockLetters(); AppStorage.setOrCreateLetter[](letters, letters); // 4. 从 letters 实时计算统计数据 const stats DataStore.computeStats(letters); AppStorage.setOrCreateWriteStats(writeStats, stats); } static addLetter(letter: Letter): void { // 原有逻辑不变 const letters: Letter[] AppStorage.getLetter[](letters) ?? []; letter.id letters.length 0 ? Math.max(...letters.map((l: Letter) l.id)) 1 : 1; letters.unshift(letter); AppStorage.setLetter[](letters, letters); // 同步更新笔友统计 const penPals: PenPal[] AppStorage.getPenPal[](penPals) ?? []; const idx penPals.findIndex((p: PenPal) p.id letter.penPalId); if (idx 0) { penPals[idx].totalLetters 1; penPals[idx].lastLetterAt letter.createdAt; penPals[idx].lastLetterPreview letter.body.substring(0, 30); penPals[idx].lastLetterStatus LetterStatus.WAITING_OTHER; penPals[idx].isLastLetterSender true; AppStorage.setPenPal[](penPals, penPals); } } }七、从 AppStorage 到 PersistentStorage 的迁移路径7.1 迁移步骤识别持久化需求确定哪些数据需要持久化注册 PersistentStorage key用persistProp注册序列化复杂对象Observed类实例需要序列化迁移数据把 AppStorage 中的数据同步到 PersistentStorage测试验证数据持久化是否正确7.2 序列化与反序列化// 写入时序列化 function savePenPals(penPals: PenPal[]): void { const json JSON.stringify(penPals); AppStorage.setstring(saved_penPals, json); } // 读取时反序列化 function loadPenPals(): PenPal[] { const json AppStorage.getstring(saved_penPals) ?? []; const data JSON.parse(json) as ArrayRecordstring, Object; return data.map((item) { const pal new PenPal(); Object.assign(pal, item); return pal; }); }八、LocalStorage 在 xiexin 中的应用8.1 场景ComposePage 的草稿管理xiexin 的 ComposePage 有 14 个State变量如果使用 LocalStorage 来管理草稿可以简化代码// 创建页面级 LocalStorage const composeStorage new LocalStorage(); composeStorage.setOrCreate(penPalId, -1); composeStorage.setOrCreate(body, ); composeStorage.setOrCreate(honorific, 尊敬的); composeStorage.setOrCreate(greeting, 您好); composeStorage.setOrCreate(closing, 此致\n敬礼); composeStorage.setOrCreate(paperStyle, PaperStyle.PLAIN); composeStorage.setOrCreate(wordCount, 0); Entry(composeStorage) Component struct ComposePage { LocalStorageProp(penPalId) selectedPenPalId: number -1; LocalStorageProp(body) body: string ; LocalStorageProp(honorific) honorific: string 尊敬的; LocalStorageProp(greeting) greeting: string 您好; LocalStorageProp(closing) closing: string 此致\n敬礼; LocalStorageProp(paperStyle) paperStyle: PaperStyle PaperStyle.PLAIN; LocalStorageProp(wordCount) wordCount: number 0; // ... 其他逻辑 }8.2 LocalStorage 与 AppStorage 的配合// 页面销毁时保存草稿到 AppStorage aboutToDisappear(): void { if (this.body.length 50) { AppStorage.setOrCreate(draft, { penPalId: this.selectedPenPalId, body: this.body, honorific: this.honorific, greeting: this.greeting, closing: this.closing, paperStyle: this.paperStyle, savedAt: Date.now() }); } }九、三级存储的性能对比9.1 读写性能存储层级读性能写性能说明AppStorage纳秒级纳秒级内存操作极快LocalStorage纳秒级纳秒级内存操作极快PersistentStorage微秒级微秒级磁盘 IO较慢9.2 内存占用AppStorage/LocalStorage数据在内存中占用应用进程内存PersistentStorage数据在磁盘上仅当被访问时加载到内存9.3 选型建议// 高频读写、不持久化 → AppStorage AppStorage.set(currentTab, index); // 低频读写、需要持久化 → PersistentStorage PersistentStorage.persistProp(hasSeenSplash, false); // 页面内共享、页面销毁可丢弃 → LocalStorage const pageStorage new LocalStorage(); pageStorage.setOrCreate(draft, );十、从 xiexin 看存储架构设计xiexin 当前的存储架构仅 AppStorage适合演示和原型阶段。如果要落地为真实应用建议按以下优先级改造短期1-2 周引入 PersistentStorage持久化hasSeenSplash和currentTab中期1-2 月引入 RDB 数据库替代数组存储的笔友和信件数据长期3-6 月引入分布式数据对象实现跨设备数据同步总结本文详细剖析了 HarmonyOS ArkUI 的 AppStorage/PersistentStorage/LocalStorage 三级存储的语义、差异和选型策略。xiexin 当前仅使用 AppStorage 的架构适合演示阶段但通过引入 PersistentStorage 和 LocalStorage可以显著提升数据持久化能力和页面隔离性。理解三级存储的关键是把握“三个维度“生命周期进程/持久化/页面、作用范围应用/页面、数据流向双向/单向。掌握了这三个维度就能在不同场景中选出最合适的存储方案。下一篇文章我们将深入 ForEach 列表渲染剖析键值策略与 Diff 算法的实现细节。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netHarmonyOS AppStorage 全局状态https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-appstorageHarmonyOS PersistentStorage 持久化https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-persiststorageHarmonyOS LocalStorage 页面级存储https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-localstorageHarmonyOS 状态管理概述https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state-management-overviewHarmonyOS 应用数据持久化https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/app-data-persistenceHarmonyOS 通过用户首选项实现持久化https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/data-persistence-by-preferencesHarmonyOS 分布式数据对象https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/data-sync-of-distributed-data-objectHarmonyOS 关系型数据库https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/data-persistence-by-rdb-store