首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

鸿蒙HarmonyOS开发框架—ArkTS语言(状态管理 六)

  • 25-02-22 03:20
  • 2092
  • 12725
blog.csdn.net

AppStorage:应用全局的UI状态存储

AppStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。

和LocalStorage不同的是,LocalStorage是页面级的,通常应用于页面内的数据共享。而对于AppStorage,是应用级的全局状态共享。

概述

AppStorage是在应用启动的时候会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorage将在应用运行过程保留其属性。属性通过唯一的键字符串值访问。

AppStorage可以和UI组件同步,且可以在应用业务逻辑中被访问。

AppStorage中的属性可以被双向同步,数据可以是存在于本地或远程设备上,并具有不同的功能,比如数据持久化。

@StorageProp

在上文中已经提到,如果要建立AppStorage和自定义组件的联系,需要使用@StorageProp和@StorageLink装饰器。使用@StorageProp(key)/@StorageLink(key)装饰组件内的变量,key标识了AppStorage的属性。

当自定义组件初始化的时候,@StorageProp(key)/@StorageLink(key)装饰的变量会通过给定的key,绑定在AppStorage对应的属性,完成初始化。本地初始化是必要的,因为无法保证AppStorage一定存在给定的key,这取决于应用逻辑,是否在组件初始化之前在AppStorage实例中存入对应的属性。

@StorageProp(key)是和AppStorage中key对应的属性建立单向数据同步,我们允许本地改变的发生,但是对于@StorageProp,本地的修改永远不会同步回AppStorage中,相反,如果AppStorage给定key的属性发生改变,改变会被同步给@StorageProp,并覆盖掉本地的修改。

装饰器使用规则说明

@StorageProp变量装饰器

说明

装饰器参数

key:常量字符串,必填(字符串需要有引号)。

允许装饰的变量类型

Object class、string、number、boolean、enum类型,以及这些类型的数组。 类型必须被指定,且必须和LocalStorage中对应属性相同。不支持any,不允许使用undefined和null。

同步类型

单向同步:从AppStorage的对应属性到组件的状态变量。 组件本地的修改是允许的,但是AppStorage中给定的属性一旦发生变化,将覆盖本地的修改。

被装饰变量的初始值

必须指定,如果AppStorage实例中不存在属性,则作为初始化默认值,并存入AppStorage中。

变量的传递/访问规则说明

传递/访问

说明

从父节点初始化和更新

禁止,@StorageProp不支持从父节点初始化,只能AppStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化

初始化子节点

支持,可用于初始化@State、@Link、@Prop、@Provide。

是否支持组件外访问

否。

图1 @StorageProp初始化规则图示

观察变化和行为表现

观察变化

  • 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
  • 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性。
  • 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。

框架行为

  • 当@StorageProp(key)装饰的数值改变被观察到时,修改不会被同步回AppStorage对应属性键值key的属性中。
  • 当前@StorageProp(key)单向绑定的数据会被修改,即仅限于当前组件的私有成员变量改变,其他的绑定该key的数据不会同步改变。
  • 当@StorageProp(key)装饰的数据本身是状态变量,它的改变虽然不会同步回AppStorage中,但是会引起所属的自定义组件的重新渲染。
  • 当AppStorage中key对应的属性发生改变时,会同步给所有@StorageProp(key)装饰的数据,@StorageProp(key)本地的修改将被覆盖。
@StorageLink

@StorageLink(key)是和AppStorage中key对应的属性建立双向数据同步:

  1. 本地修改发生,该修改会被写回AppStorage中;
  2. AppStorage中的修改发生后,该修改会被同步到所有绑定AppStorage对应key的属性上,包括单向(@StorageProp和通过Prop创建的单向绑定变量)、双向(@StorageLink和通过Link创建的双向绑定变量)变量和其他实例(比如PersistentStorage)。
装饰器使用规则说明

@StorageLink变量装饰器

说明

装饰器参数

key:常量字符串,必填(字符串需要有引号)。

允许装饰的变量类型

Object、class、string、number、boolean、enum类型,以及这些类型的数组。 类型必须被指定,且必须和AppStorage中对应属性相同。不支持any,不允许使用undefined和null。

同步类型

双向同步:从AppStorage的对应属性到自定义组件,从自定义组件到AppStorage对应属性。

被装饰变量的初始值

必须指定,如果AppStorage实例中不存在属性,则作为初始化默认值,并存入AppStorage中。

变量的传递/访问规则说明

传递/访问

说明

从父节点初始化和更新

禁止。

初始化子节点

支持,可用于初始化常规变量、@State、@Link、@Prop、@Provide。

是否支持组件外访问

否。

图2 @StorageLink初始化规则图示

观察变化和行为表现

观察变化

  • 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
  • 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性。
  • 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。

框架行为

  1. 当@StorageLink(key)装饰的数值改变被观察到时,修改将被同步回AppStorage对应属性键值key的属性中。
  2. AppStorage中属性键值key对应的数据一旦改变,属性键值key绑定的所有的数据(包括双向@StorageLink和单向@StorageProp)都将同步修改;
  3. 当@StorageLink(key)装饰的数据本身是状态变量,它的改变不仅仅会同步回AppStorage中,还会引起所属的自定义组件的重新渲染。
使用场景
从应用逻辑使用AppStorage和LocalStorage

AppStorage是单例,它的所有API都是静态的,使用方法类似于LocalStorage对应的非静态方法。

  1. AppStorage.SetOrCreate('PropA', 47);
  2. let storage: LocalStorage = new LocalStorage({ 'PropA': 17 });
  3. let propA: number = AppStorage.Get('PropA') // propA in AppStorage == 47, propA in LocalStorage == 17
  4. var link1: SubscribedAbstractProperty<number> = AppStorage.Link('PropA'); // link1.get() == 47
  5. var link2: SubscribedAbstractProperty<number> = AppStorage.Link('PropA'); // link2.get() == 47
  6. var prop: SubscribedAbstractProperty<number> = AppStorage.Prop('PropA'); // prop.get() = 47
  7. link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
  8. prop.set(1); // one-way sync: prop.get()=1; but link1.get() == link2.get() == 48
  9. link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
  10. storage.get('PropA') // == 17
  11. storage.set('PropA', 101);
  12. storage.get('PropA') // == 101
  13. AppStorage.Get('PropA') // == 49
  14. link1.get() // == 49
  15. link2.get() // == 49
  16. prop.get() // == 49

复制

从UI内部使用AppStorage和LocalStorage

@StorageLink变量装饰器与AppStorage配合使用,正如@LocalStorageLink与LocalStorage配合使用一样。此装饰器使用AppStorage中的属性创建双向数据同步。

  1. AppStorage.SetOrCreate('PropA', 47);
  2. let storage = new LocalStorage({ 'PropA': 48 });
  3. @Entry(storage)
  4. @Component
  5. struct CompA {
  6. @StorageLink('PropA') storLink: number = 1;
  7. @LocalStorageLink('PropA') localStorLink: number = 1;
  8. build() {
  9. Column({ space: 20 }) {
  10. Text(`From AppStorage ${this.storLink}`)
  11. .onClick(() => this.storLink += 1)
  12. Text(`From LocalStorage ${this.localStorLink}`)
  13. .onClick(() => this.localStorLink += 1)
  14. }
  15. }
  16. }

复制

以持久化方式订阅某个事件并接收事件回调

推荐使用持久化方式订阅某个事件并接收事件回调,可以减少开销,增强代码的可读性。

  1. // xxx.ets
  2. import emitter from '@ohos.events.emitter';
  3. let NextID: number = 0;
  4. class ViewData {
  5. title: string;
  6. uri: Resource;
  7. color: Color = Color.Black;
  8. id: number;
  9. constructor(title: string, uri: Resource) {
  10. this.title = title;
  11. this.uri = uri
  12. this.id = NextID++;
  13. }
  14. }
  15. @Entry
  16. @Component
  17. struct Gallery2 {
  18. dataList: Array<ViewData> = [new ViewData('flower', $r('app.media.icon')), new ViewData('OMG', $r('app.media.icon')), new ViewData('OMG', $r('app.media.icon'))]
  19. scroller: Scroller = new Scroller()
  20. private preIndex: number = -1
  21. build() {
  22. Column() {
  23. Grid(this.scroller) {
  24. ForEach(this.dataList, (item: ViewData) => {
  25. GridItem() {
  26. TapImage({
  27. uri: item.uri,
  28. index: item.id
  29. })
  30. }.aspectRatio(1)
  31. .onClick(() => {
  32. if (this.preIndex === item.id) {
  33. return
  34. }
  35. var innerEvent = { eventId: item.id }
  36. // 选中态:黑变红
  37. var eventData = {
  38. data: {
  39. "colorTag": 1
  40. }
  41. }
  42. emitter.emit(innerEvent, eventData)
  43. if (this.preIndex != -1) {
  44. console.info(`preIndex: ${this.preIndex}, index: ${item.id}, black`)
  45. var innerEvent = { eventId: this.preIndex }
  46. // 取消选中态:红变黑
  47. var eventData = {
  48. data: {
  49. "colorTag": 0
  50. }
  51. }
  52. emitter.emit(innerEvent, eventData)
  53. }
  54. this.preIndex = item.id
  55. })
  56. }, (item: ViewData) => JSON.stringify(item))
  57. }.columnsTemplate('1fr 1fr')
  58. }
  59. }
  60. }
  61. @Component
  62. export struct TapImage {
  63. @State tapColor: Color = Color.Black;
  64. private index: number;
  65. private uri: Resource;
  66. onTapIndexChange(colorTag: emitter.EventData) {
  67. this.tapColor = colorTag.data.colorTag ? Color.Red : Color.Black
  68. }
  69. aboutToAppear() {
  70. //定义事件ID
  71. var innerEvent = { eventId: this.index }
  72. emitter.on(innerEvent, this.onTapIndexChange.bind(this))
  73. }
  74. build() {
  75. Column() {
  76. Image(this.uri)
  77. .objectFit(ImageFit.Cover)
  78. .border({ width: 5, style: BorderStyle.Dotted, color: this.tapColor })
  79. }
  80. }
  81. }

复制

以下示例为消息机制方式订阅事件,会导致回调监听的节点数较多,非常耗时,不推荐以此来实现应用代码。

  1. // xxx.ets
  2. class ViewData {
  3. title: string;
  4. uri: Resource;
  5. color: Color = Color.Black;
  6. constructor(title: string, uri: Resource) {
  7. this.title = title;
  8. this.uri = uri
  9. }
  10. }
  11. @Entry
  12. @Component
  13. struct Gallery2 {
  14. dataList: Array<ViewData> = [new ViewData('flower', $r('app.media.icon')), new ViewData('OMG', $r('app.media.icon')), new ViewData('OMG', $r('app.media.icon'))]
  15. scroller: Scroller = new Scroller()
  16. build() {
  17. Column() {
  18. Grid(this.scroller) {
  19. ForEach(this.dataList, (item: ViewData, index?: number) => {
  20. GridItem() {
  21. TapImage({
  22. uri: item.uri,
  23. index: index
  24. })
  25. }.aspectRatio(1)
  26. }, (item: ViewData, index?: number) => {
  27. return JSON.stringify(item) + index;
  28. })
  29. }.columnsTemplate('1fr 1fr')
  30. }
  31. }
  32. }
  33. @Component
  34. export struct TapImage {
  35. @StorageLink('tapIndex') @Watch('onTapIndexChange') tapIndex: number = -1;
  36. @State tapColor: Color = Color.Black;
  37. private index: number;
  38. private uri: Resource;
  39. // 判断是否被选中
  40. onTapIndexChange() {
  41. if (this.tapIndex >= 0 && this.index === this.tapIndex) {
  42. console.info(`tapindex: ${this.tapIndex}, index: ${this.index}, red`)
  43. this.tapColor = Color.Red;
  44. } else {
  45. console.info(`tapindex: ${this.tapIndex}, index: ${this.index}, black`)
  46. this.tapColor = Color.Black;
  47. }
  48. }
  49. build() {
  50. Column() {
  51. Image(this.uri)
  52. .objectFit(ImageFit.Cover)
  53. .onClick(() => {
  54. this.tapIndex = this.index;
  55. })
  56. .border({ width: 5, style: BorderStyle.Dotted, color: this.tapColor })
  57. }
  58. }
  59. }

复制

限制条件

AppStorage与PersistentStorage以及Environment配合使用时,需要注意以下几点:

  • 在AppStorage中创建属性后,调用PersistentStorage.PersistProp()接口时,会使用在AppStorage中已经存在的值,并覆盖PersistentStorage中的同名属性,所以建议要使用相反的调用顺序;
  • 如果在AppStorage中已经创建属性后,再调用Environment.EnvProp()创建同名的属性,会调用失败。因为AppStorage已经有同名属性,Environment环境变量不会再写入AppStorage中,所以建议AppStorage中属性不要使用Environment预置环境变量名。

最后,为了能让大家更好的去学习提升鸿蒙 (Harmony OS) 开发技术,小编连夜整理了一份30个G纯血版学习资料(含视频、电子书、学习文档等)以及一份在Github上持续爆火霸榜的《纯血版华为鸿蒙 (Harmony OS)开发手册》(共计890页),希望对大家有所帮助。

纯血版鸿蒙 HarmonyOS 4.0 视频学习资料

 需要以上视频学习资料小伙伴

请点击→纯血版全套鸿蒙HarmonyOS学习资料


《纯血版华为鸿蒙 (Harmony OS)开发手册》

这份手册涵盖了当前鸿蒙 (Harmony OS) 开发技术必掌握的核心知识点

纯血版鸿蒙 (Harmony OS)开发手册部分精彩内容

HarmonyOS 概念:

  • 系统定义
  • 技术架构
  • 技术特性
  • 系统安全

如何快速入门?

  • 基本概念
  • 构建第一个ArkTS应用
  • 构建第一个JS应用
  • ……


开发基础知识: 

  • 应用基础知识
  • 配置文件
  • 应用数据管理
  • 应用安全管理
  • 应用隐私保护
  • 三方应用调用管控机制
  • 资源分类与访问
  • 学习ArkTS语言
  • ……

基于ArkTS 开发:

  • Ability开发
  • UI开发
  • 公共事件与通知
  • 窗口管理
  • 媒体
  • 安全
  • 网络与链接
  • 电话服务
  • 数据管理
  • 后台任务(Background Task)管理
  • 设备管理
  • 设备使用信息统计
  • DFX
  • 国际化开发
  • 折叠屏系列
  • .……

获取以上文中提到的这份纯血版鸿蒙 (Harmony OS) 开发资料的小伙伴 

请点击→纯血版全套鸿蒙HarmonyOS学习资料


?写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing?,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新VIP学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

最新鸿蒙Next全套学习资料请扫码
微信名片
注:本文转载自blog.csdn.net的蜀道山QAQ的文章"https://blog.csdn.net/shudaoshanQAQ/article/details/135637455"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top