HarmonyOS 应用级状态管理(LocalStorage、AppStorage、PersistentStorage ...

打印 上一主题 下一主题

主题 1015|帖子 1015|积分 3045

HarmonyOS 应用级状态管理

1. LocalStorage:页面级UI状态存储

1.1 概念



  • LocalStorage是页面级的UI状态存储,通过@Entry装饰器吸收的参数可以在页面内共享同一个LocalStorage实例。LocalStorage也可以在UIAbility内,页面间共享状态。

    • 应用步伐可以创建多个LocalStorage实例,LocalStorage实例可以在页面内共享,也可以通过GetShared接口,获取在UIAbility里创建的GetShared,实现跨页面、UIAbility内共享。
    • 组件树的根节点,即被@Entry装饰的@Component,可以被分配一个LocalStorage实例,此组件的所有子组件实例将自动得到对该LocalStorage实例的访问权限;
    • 被@Component装饰的组件最多可以访问一个LocalStorage实例和AppStorage,未被@Entry装饰的组件不可被独立分配LocalStorage实例,只能接受父组件通过@Entry传递来的LocalStorage实例。一个LocalStorage实例在组件树上可以被分配给多个组件。
    • LocalStorage中的所有属性都是可变的

1.2 应用逻辑使用LocalStorage

  1. /**
  2. * 和 js 用法几乎一致
  3. * 初始化的时候需要传入一个对象使用
  4. * 修改的时候通过key 修改 value的值
  5. */
  6. const storage = new LocalStorage({name: "李四"})
  7. storage.set('name', '张三')
  8. console.log(storage.get("name"))
  9. @Entry
  10. @Component
  11. struct LearnStorage {
  12.   @State message: string = 'Hello World'
  13.   build() {
  14.     Row() {
  15.       Column() {
  16.         Text(this.message)
  17.           .fontSize(50)
  18.           .fontWeight(FontWeight.Bold)
  19.       }
  20.       .width('100%')
  21.     }
  22.     .height('100%')
  23.   }
  24. }
复制代码
1.3 从UI内部使用LocalStorage(双向同步)



  • 除了应用步伐逻辑使用LocalStorage,还可以借助LocalStorage相干的两个装饰器@LocalStorageProp和@LocalStorageLink,在UI组件内部获取到LocalStorage实例中存储的状态变量。


1.3.1 例子



  • 使用构造函数创建LocalStorage实例storage;
  • 使用@Entry装饰器将storage添加到LearnStorage顶层组件中;
  • @LocalStorageLink绑定LocalStorage对给定的属性,建立双向数据同步
  1. @Component
  2. struct Child {
  3.   // 子组件可以直接使用
  4.   @LocalStorageLink('name') storageName: string = '张三';
  5.   build() {
  6.     Column() {
  7.       Text('子组件---'+this.storageName)
  8.     }
  9.   }
  10. }
  11. /**
  12. * 和 js 用法几乎一致
  13. * 初始化的时候需要传入一个对象使用
  14. * 修改的时候通过key 修改 value的值
  15. */
  16. const storage = new LocalStorage({})
  17. @Entry(storage)
  18. @Component
  19. struct LearnStorage {
  20.   /**
  21.    * @LocalStorageLink变量装饰器与LocalStorage中的'name'属性建立双向绑定
  22.    * 当@LocalStorageLink(key)装饰的数值改变被观察到时,修改将被同步回LocalStorage对应属性键值key的属性中。
  23.    LocalStorage中属性键值key对应的数据一旦改变,属性键值key绑定的所有的数据(包括双向@LocalStorageLink和单向@LocalStorageProp)都将同步修改;
  24.    当@LocalStorageLink(key)装饰的数据本身是状态变量,它的改变不仅仅会同步回LocalStorage中,还会引起所属的自定义组件的重新渲染
  25.       必须指定默认值,如果localstorage对应的key里面有值优先取localstorage里面的值,没有则使用默认值
  26.    */
  27.   @LocalStorageLink('name') storageName: string = '张三';
  28.   build() {
  29.     Row() {
  30.       Column() {
  31.         Text(this.storageName)
  32.           .fontSize(50)
  33.           .fontWeight(FontWeight.Bold)
  34.         Button('看看Storage').onClick(() => {
  35.           this.storageName = '王五'
  36.           // 也会打印王五
  37.           console.log(storage.get('name'))
  38.         })
  39.         Child()
  40.       }
  41.       .width('100%')
  42.     }
  43.     .height('100%')
  44.   }
  45. }
复制代码
1.4 从UI内部使用LocalStorage(单向同步)

  1. @Component
  2. struct Child {
  3.   // 子组件可以直接使用
  4.   @LocalStorageProp('name') storageName: string = '张三';
  5.   build() {
  6.     Column() {
  7.       Text('子组件---'+this.storageName)
  8.     }
  9.   }
  10. }
  11. /**
  12. * 和 js 用法几乎一致
  13. * 初始化的时候需要传入一个对象使用
  14. * 修改的时候通过key 修改 value的值
  15. */
  16. const storage = new LocalStorage({})
  17. @Entry(storage)
  18. @Component
  19. struct LearnStorage {
  20.   /**
  21.    必须指定默认值,如果localstorage对应的key里面有值优先取localstorage里面的值,没有则使用默认值
  22.    */
  23.   @LocalStorageProp('name') storageName: string = '张三';
  24.   build() {
  25.     Row() {
  26.       Column() {
  27.         Text(this.storageName)
  28.           .fontSize(50)
  29.           .fontWeight(FontWeight.Bold)
  30.         Button('看看Storage').onClick(() => {
  31.           this.storageName = '王五'
  32.           // 单项同步不会修改storage里的数据
  33.           console.log(storage.get('name'))
  34.         })
  35.         Child()
  36.       }
  37.       .width('100%')
  38.     }
  39.     .height('100%')
  40.   }
  41. }
复制代码
1.5 将LocalStorage实例从UIAbility共享到一个或多个视图(全局共享)



  • 上面的实例中,LocalStorage的实例仅仅在一个@Entry装饰的组件和其所属的子组件(一个页面)中共享,如果希望其在多个视图中共享,可以在所属UIAbility中创建LocalStorage实例,并调用windowStage.loadContent。
1.5.1 EntryAbility

  1. import UIAbility from '@ohos.app.ability.UIAbility';
  2. import hilog from '@ohos.hilog';
  3. import window from '@ohos.window';
  4. // 创建storage
  5. const localStorage: LocalStorage = new LocalStorage({globalName: "全局的名字"});
  6. export default class EntryAbility extends UIAbility {
  7.   // 挂载到实例里
  8.   storage: LocalStorage = localStorage
  9.   onCreate(want, launchParam) {
  10.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  11.   }
  12.   onDestroy() {
  13.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  14.   }
  15.   async onWindowStageCreate(windowStage: window.WindowStage) {
  16.     windowStage.loadContent('pages/LearnStorage', this.storage);
  17.   }
  18.   onWindowStageDestroy() {
  19.     // Main window is destroyed, release UI related resources
  20.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  21.   }
  22.   onForeground() {
  23.     // Ability has brought to foreground
  24.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  25.   }
  26.   onBackground() {
  27.     // Ability has back to background
  28.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  29.   }
  30. }
复制代码
1.5.2 页面中使用

  1. // 通过GetShared接口获取stage共享的LocalStorage实例
  2. const storage = LocalStorage.GetShared()
  3. console.log(JSON.stringify(storage))
  4. // 注入
  5. @Entry(storage)
  6. @Component
  7. struct LearnStorage {
  8.   /**
  9.       注意:要在模拟器中运行
  10.     使用prop单项绑定 或者 link双向绑定
  11.    */
  12.   @LocalStorageLink('globalName') globalName: string = '李四';
  13.   // globalName = 'aa'
  14.   build() {
  15.     Row() {
  16.       Column() {
  17.         Text(this.globalName)
  18.           .fontSize(50)
  19.           .fontWeight(FontWeight.Bold)
  20.         Button('看看Storage').onClick(() => {
  21.           this.globalName = '王五'
  22.           // 单项同步不会修改storage里的数据
  23.           console.log(storage.get('name'))
  24.         })
  25.       }
  26.       .width('100%')
  27.     }
  28.     .height('100%')
  29.   }
  30. }
复制代码
2.AppStorage:应用全局的UI状态存储

2.1 概念



  • AppStorage是应用全局的UI状态存储,是和应用的历程绑定的,由UI框架在应用步伐启动时创建,为应用步伐UI状态属性提供中心存储。
  • 和AppStorage不同的是,LocalStorage是页面级的,通常应用于页面内的数据共享。而AppStorage是应用级的全局状态共享,还相称于整个应用的“中枢”,长期化数据PersistentStorage和环境变量Environment都是通过和AppStorage中转,才可以和UI交互。
  • AppStorage是在应用启动的时候会被创建的单例。它的目标是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorage将在应用运行过程保留其属性。属性通过唯一的键字符串值访问。
  • AppStorage可以和UI组件同步,且可以在应用业务逻辑中被访问。
  • AppStorage中的属性可以被双向同步,数据可以是存在于本地或远程设备上,并具有不同的功能,比如数据长期化(详见PersistentStorage)。这些数据是通过业务逻辑中实现,与UI解耦,如果希望这些数据在UI中使用,需要用到@StorageProp和@StorageLink
2.2 从应用逻辑使用AppStorage



  • AppStorage是单例,它的所有API都是静态的
  1. // 有则修改没有则创建
  2. AppStorage.SetOrCreate('name', 'app的名字');
  3. console.log(AppStorage.Get('name'))
  4. @Entry()
  5. @Component
  6. struct LearnStorage {
  7.   build() {
  8.     Row() {
  9.       Column() {
  10.         Text('哈哈哈')
  11.       }
  12.       .width('100%')
  13.     }
  14.     .height('100%')
  15.   }
  16. }
复制代码
2.3 从UI内部使用AppStorage



  • @StorageLink变量装饰器与AppStorage配合使用,正如@LocalStorageLink与LocalStorage配合使用一样。此装饰器使用AppStorage中的属性创建双向数据同步
  1. // 有则修改没有则创建
  2. AppStorage.SetOrCreate('name', 'app的名字');
  3. console.log(AppStorage.Get('name'))
  4. @Entry()
  5. @Component
  6. struct LearnStorage {
  7.   /**
  8.    * 对AppStorage 里面的数据进行双向绑定
  9.    * 同样使用prop为单向数据流
  10.    */
  11.   @StorageLink('name') name: string = '李四'
  12.   build() {
  13.     Row() {
  14.       Column() {
  15.         Text(this.name)
  16.         Button('查看数据')
  17.           .onClick(() => {
  18.             this.name = '王五'
  19.             // 数据也会改变
  20.             console.log(AppStorage.Get('name'))
  21.           })
  22.       }
  23.       .width('100%')
  24.     }
  25.     .height('100%')
  26.   }
  27. }
复制代码
3.PersistentStorage:长期化存储UI状态

3.1 概念



  • PersistentStorage将选定的AppStorage属性保留在设备磁盘上。应用步伐通过API,以决定哪些AppStorage属性应借助PersistentStorage长期化。UI和业务逻辑不直接访问PersistentStorage中的属性,所有属性访问都是对AppStorage的访问,AppStorage中的更改会自动同步到PersistentStorage。
  • PersistentStorage和AppStorage中的属性建立双向同步。应用开发通常通过AppStorage访问PersistentStorage,另外还有一些接口可以用于管理长期化属性,但是业务逻辑始终是通过AppStorage获取和设置属性的。
3.2 留意

3.2.1 允许的类型和值




    • 使用简单类型如 number, string, boolean, enum。


    • 可以使用 JSON.stringify() 和 JSON.parse() 的对象,但不支持内置类型如 Date, Map, Set。

3.2.2 不允许的类型和值




    • 避免嵌套对象,包括对象数组和对象属性是对象。


    • 不支持 undefined 和 null。

3.2.3 最佳实践和限定




    • 避免长期化大型和经常变化的数据。


    • 长期化变量最好小于 2kb。


    • 不要过度长期化数据,可能影响 UI 渲染性能。


    • 对于大量数据存储需求,建议使用数据库 API。


    • 仅在 UI 页面内使用 PersistentStorage,否则无法长期化数据

3.3 使用

  1. // 存入的数据会一直存在
  2. PersistentStorage.PersistProp('token', '后端获取的token');
  3. // 可以使用AppStorage 进行获取
  4. console.log(AppStorage.Get('token'))
  5. // 这样定义的不会持久化,应用被杀死 数据会丢失
  6. // AppStorage.SetOrCreate('token', '小token')
  7. @Entry()
  8. @Component
  9. struct LearnStorage {
  10.   /**
  11.    * 双向绑定
  12.    * 也可以是会用StorageLink进行获取
  13.    */
  14.   @StorageLink('token') token: string = ''
  15.   build() {
  16.     Row() {
  17.       Column() {
  18.         Text(this.token)
  19.         Button('修改数据')
  20.           .onClick(() => {
  21.             this.token = '修改的token,并且持久化'
  22.           })
  23.       }
  24.       .width('100%')
  25.     }
  26.     .height('100%')
  27.   }
  28. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表