当前位置: 首页 > article >正文

OpenHarmony 入门——ArkUI 跨页面数据同步和应用全局单例的UI状态存储AppStorage 小结(三)

文章大纲

  • 引言
  • 一、AppStorage 应用全局的UI状态存储
    • 1、@StorageProp和@StorageLink装饰器建立联系
    • 2、@StorageProp
      • 2.1、@StorageProp使用规则
      • 2.2、@StorageProp变量的传递/访问规则
      • 2.3、@StorageProp支持的观察变化
      • 2.4、@StorageProp 值初始化和更新
    • 3、@StorageLink
      • 3.1、@StorageLink使用规则
      • 3.2、@StorageLink变量的传递/访问规则
      • 3.3、@StorageLink支持的观察变化
      • 3.4、@StorageLink 值初始化和更新
    • 4、AppStorage与PersistentStorage以及Environment配合使用时的注意事项
  • 二、AppStorage 的应用
    • 1、在代码逻辑使用AppStorage和LocalStorage
    • 2、从UI内部使用AppStorage和LocalStorage

引言

前面文章介绍了跨页面之间的数据同步和状态存储机制LocalStorageOpenHarmony 入门——ArkUI 跨页面数据同步和页面级UI状态存储LocalStorage小结(二)的基础语法和使用,这一篇介绍了应用进程级别的状态存储机制AppStorage。

一、AppStorage 应用全局的UI状态存储

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

1、@StorageProp和@StorageLink装饰器建立联系

原理其实和LocalStorage中的@LocalStorageProp和@LocalStorageLink大同小异,都是通过各自的装饰器建立联系从而完成数据同步和状态存储。

如果要建立AppStorage和自定义组件的联系,需要使用**@StorageProp和@StorageLink装饰器。使用@StorageProp(key)/@StorageLink(key)装饰组件内的变量,key标识了AppStorage的属性。当自定义组件初始化的时候,会使用AppStorage中对应key的属性值将@StorageProp(key)/@StorageLink(key)装饰的变量初始化。由于应用逻辑的差异,无法确认是否在组件初始化之前向AppStorage实例中存入了对应的属性,所以AppStorage不一定存在key对应的属性,因此@StorageProp(key)/@StorageLink(key)装饰的变量必须进行本地初始化**。@StorageProp(key)是和AppStorage中key对应的属性建立单向数据同步,允许本地改变,但是对于@StorageProp,本地的修改永远不会同步回AppStorage中,相反,如果AppStorage给定key的属性发生改变,改变会被同步给@StorageProp,并覆盖掉本地的修改。

2、@StorageProp

2.1、@StorageProp使用规则

在这里插入图片描述

2.2、@StorageProp变量的传递/访问规则

在这里插入图片描述
在这里插入图片描述

2.3、@StorageProp支持的观察变化

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

2.4、@StorageProp 值初始化和更新

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

3、@StorageLink

3.1、@StorageLink使用规则

在这里插入图片描述

3.2、@StorageLink变量的传递/访问规则

在这里插入图片描述

3.3、@StorageLink支持的观察变化

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

3.4、@StorageLink 值初始化和更新

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

4、AppStorage与PersistentStorage以及Environment配合使用时的注意事项

  • 在AppStorage中创建属性后,调用PersistentStorage.persistProp()接口时,会使用在AppStorage中已经存在的值,并覆盖PersistentStorage中的同名属性,所以建议要使用相反的调用顺序,反例可见在PersistentStorage之前访问AppStorage中的属性;
  • 如果在AppStorage中已经创建属性后,再调用Environment.envProp()创建同名的属性,会调用失败。因为AppStorage已经有同名属性,Environment环境变量不会再写入AppStorage中,所以建议AppStorage中属性不要使用Environment预置环境变量名。
  • 状态装饰器装饰的变量,改变会引起UI的渲染更新,如果改变的变量不是用于UI更新,只是用于消息传递,推荐使用 emitter方式。例子可见不建议借助@StorageLink的双向同步机制实现事件通知。

二、AppStorage 的应用

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

1、在代码逻辑使用AppStorage和LocalStorage

AppStorage.setOrCreate('PropA', 47);let storage: LocalStorage = new LocalStorage();
storage.setOrCreate('PropA',17);
let propA: number | undefined = AppStorage.get('PropA') // propA in AppStorage == 47, propA in LocalStorage == 17
let link1: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link1.get() == 47
let link2: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link2.get() == 47
let prop: SubscribedAbstractProperty<number> = AppStorage.prop('PropA'); // prop.get() == 47link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48
link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49storage.get<number>('PropA') // == 17
storage.set('PropA', 101);
storage.get<number>('PropA') // == 101AppStorage.get<number>('PropA') // == 49
link1.get() // == 49
link2.get() // == 49
prop.get() // == 49

2、从UI内部使用AppStorage和LocalStorage

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

代码就不写了,除了创建和使用的装饰器不一样其他都一样

  • AppStorage.setOrCreate函数创建AppStorage 实例

不建议开发者使用@StorageLink和AppStorage的双向同步的机制来实现事件通知,因为AppStorage中的变量可能绑定在多个不同页面的组件中,但事件通知则不一定需要通知到所有的这些组件。并且,当这些@StorageLink装饰的变量在UI中使用时,会触发UI刷新,带来不必要的性能影响。开发者可以使用emit订阅某个事件并接收事件回调的方式来减少开销,增强代码的可读性。

// xxx.ets
import emitter from '@ohos.events.emitter';let NextID: number = 0;class ViewData {title: string;uri: Resource;color: Color = Color.Black;id: number;constructor(title: string, uri: Resource) {this.title = title;this.uri = urithis.id = NextID++;}
}@Entry
@Component
struct Gallery2 {dataList: Array<ViewData> = [new ViewData('flower', $r('app.media.icon')), new ViewData('OMG', $r('app.media.icon')), new ViewData('OMG', $r('app.media.icon'))]scroller: Scroller = new Scroller()private preIndex: number = -1build() {Column() {Grid(this.scroller) {ForEach(this.dataList, (item: ViewData) => {GridItem() {TapImage({uri: item.uri,index: item.id})}.aspectRatio(1).onClick(() => {if (this.preIndex === item.id) {return}let innerEvent: emitter.InnerEvent = { eventId: item.id }// 选中态:黑变红let eventData: emitter.EventData = {data: {"colorTag": 1}}emitter.emit(innerEvent, eventData)if (this.preIndex != -1) {console.info(`preIndex: ${this.preIndex}, index: ${item.id}, black`)let innerEvent: emitter.InnerEvent = { eventId: this.preIndex }// 取消选中态:红变黑let eventData: emitter.EventData = {data: {"colorTag": 0}}emitter.emit(innerEvent, eventData)}this.preIndex = item.id})}, (item: ViewData) => JSON.stringify(item))}.columnsTemplate('1fr 1fr')}}
}@Component
export struct TapImage {@State tapColor: Color = Color.Black;private index: number = 0;private uri: Resource = {id: 0,type: 0,moduleName: "",bundleName: ""};onTapIndexChange(colorTag: emitter.EventData) {if (colorTag.data != null) {this.tapColor = colorTag.data.colorTag ? Color.Red : Color.Black}}aboutToAppear() {//定义事件IDlet innerEvent: emitter.InnerEvent = { eventId: this.index }emitter.on(innerEvent, data => {this.onTapIndexChange(data)})}build() {Column() {Image(this.uri).objectFit(ImageFit.Cover).border({ width: 5, style: BorderStyle.Dotted, color: this.tapColor })}}
}

相关文章:

OpenHarmony 入门——ArkUI 跨页面数据同步和应用全局单例的UI状态存储AppStorage 小结(三)

文章大纲 引言一、AppStorage 应用全局的UI状态存储1、StorageProp和StorageLink装饰器建立联系2、StorageProp2.1、StorageProp使用规则2.2、StorageProp变量的传递/访问规则2.3、StorageProp支持的观察变化2.4、StorageProp 值初始化和更新 3、StorageLink3.1、StorageLink使…...

4. 如何减少大模型幻觉?⸺大模型外挂向量数据库的分析(知识延伸版)

本文原创作者:姚瑞南 AI-agent 大模型运营专家,先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗;多年人工智能行业智能产品运营及大模型落地经验,拥有AI外呼方向国家专利与PMP项目管理证书。(转载需经授权) 目录 1. 大模型幻觉 1.1 大模型幻觉的含义 1.2 大…...

【渗透测试】Fastjson 反序列化漏洞原理(二)

目录 反序列化漏洞结合 RMI 攻击详解一、RMI 和 JNDI 的基础知识(1) RMI 简介(2) JNDI 简介 二、漏洞利用的核心原理1. 构造恶意 JSON 数据2. 设置恶意 RMI 服务3. 加载并执行恶意代码 三、具体利用过程环境准备攻击步骤1. 构造恶意 JSON 数据2. 设置恶意 RMI 服务3. 部署恶意类…...

阿里云国际站代理商:物联网设备怎样就近接入计算节点?

配置边缘计算实例 登录边缘计算控制台&#xff0c;找到已创建的边缘实例&#xff0c;点击实例名称后的“查看”。 分配OPC UA驱动到边缘实例中&#xff0c;选择OPCUA驱动&#xff0c;点击“设备列表”后的“驱动配置”&#xff0c;在弹出对话框中点击“添加通道”&#xff0c;…...

目录遍历漏洞复现

1.在fofa中输入语法&#xff0c;查询目录遍历 body"SKControlKLForJson.ashx" 查询结果为&#xff1a; 2.寻找目录遍历漏洞&#xff0c;访问网站&#xff1a; 3.我们可以app目录中下载文件等等 4.我们还可以访问其他目录的一些东西...

Java高频面试之集合-18

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;HashMap 是线程安全的吗&#xff1f;多线程下会有什么问题&#xff1f; HashMap 的线程安全性分析 HashMap 不是线程安全…...

清晰易懂的 C 语言开发环境彻底卸载与清理教程

一、卸载前的关键理解 C 语言本身是编程语言&#xff0c;无法直接“卸载”&#xff0c;但开发环境通常包含&#xff1a; 编译器&#xff08;如 GCC、Clang&#xff09;构建工具&#xff08;如 Make、CMake&#xff09;IDE 集成&#xff08;如 Visual Studio、Code::Blocks&am…...

系统思考—看见未来

感谢上海财经大学终身教育学院的持续邀请&#xff01;每个月&#xff0c;都会带着不同的思维火花&#xff0c;走进财大与学员们一起探索系统思考的奥秘。 这次为宜宾市的干部们带来了一场深刻的学习体验。通过系统思考&#xff0c;帮助大家从整体视角去发现问题、分析问题、解…...

嵌入式单片机程序的映像文件解读

映像文件类型 单片机下载程序的映像文件是包含了可执行代码、数据等信息,用于将程序烧录到单片机中的文件。常见的映像文件种类如下: 十六进制文件(Hex 文件) 格式特点:Hex 文件是一种文本格式的文件,以 ASCII 字符形式存储数据。它由一系列的记录组成,每条记录包含一个…...

保姆级教程搭建企业级智能体+私有知识库,Dify+ollama,Linux版

介绍 目前&#xff0c;AI Agent智能体已经被许多公司广泛应用&#xff0c;同时智能体借助私有知识库的加成&#xff0c;使原来知识面并不特别充分的大模型更聪明。如今特别是在医疗&#xff0c;医药&#xff0c;政企等数据保密程度高的行业&#xff0c;部署自己的私有知识库更…...

记一次线上程序宕机问题分析【写 GC 日志导致进程挂起】

1. 背景 运维侧持续反馈了几次线上业务程序 A 出现宕机告警的信息&#xff0c;重启后一段时间后又出现宕机&#xff0c;这里针对最后一次告警进行深入排查和分析。 首先这一次故障出现在 2024-03-14 04:18:23&#xff0c;和以往的宕机故障略有不同&#xff0c;以往的现象是切…...

position embedding

文章目录 1. 四种position embedding2. pytorch 源码[后续整理] 【因比较忙&#xff0c;后续整理】 1. 四种position embedding Position Embedding 1. Transformer 1.1 1d absolute 1.2 sin/cos constant 1.3 2. Vision Transformer 2.1 1d absolute 2.2 trainable 3. Swin T…...

【leetcode hot 100 739】每日温度

解法一&#xff1a;暴力解法 class Solution {public int[] dailyTemperatures(int[] temperatures) {int ntemperatures.length; // 指向要找下一个更高温度的地方int[] result new int[n];for(int left0;left<n;left){int rightleft1; // 指向正在找最高温度的地方wh…...

netplan是如何操控systemd-networkd的? 笔记250324

netplan是如何操控systemd-networkd的? netplan通过以下方式操控systemd-networkd&#xff1a; 工作原理&#xff1a;netplan读取位于/etc/netplan/目录下的YAML格式的配置文件&#xff0c;这些配置文件描述了网络接口的配置。netplan会将这些配置文件解析并转换为systemd-ne…...

Cookie、Session 与 Token:核心区别与应用场景解析

目录 引言 基础概念解析&#xff1a;三大身份验证技术详解 Cookie&#xff1a;浏览器中的"身份证" Session&#xff1a;服务器记忆的"对话" Token&#xff1a;加密的"通行证" 三种技术的深度对比分析 存储位置与数据流向 安全性全面对比…...

结合DrRacket学习《如何设计程序,第二版》

如何设计程序语言 DrRacket用于学习程序语言和设计程序语言&#xff0c;如何设计程序手册&#xff1a;How to Design Programs 如何设计程序&#xff0c;第二版&#xff1a;How to Design Programs, Second Edition 系统程序设计 设计师需遵循一系列严谨且系统的步骤&#…...

状态空间模型解析 (State-Space Model, SS)

一、文章摘要 状态空间模型&#xff08;State-Space Model, SS&#xff09;是一种广泛应用于控制系统、信号处理和系统建模的数学表示方式。MATLAB 提供的 ss 类用于描述线性时不变&#xff08;LTI&#xff09;系统的状态空间表示。本类实现了 LTI 系统的构造、属性设置、变换…...

zabbix添加IIS网站计数器(并发连接数)

0. Zabbix Agent 配置 PerfCounter = iis_Current_Connections,"\Web Service(_Total)\Current Connections",30 1.在被监控主机,powershell输入perfmon.msc 2.点击添加按钮 3.在下拉菜单中点击小箭头...

uniapp处理流式请求

在uniapp里面处理流式请求相对于web端来说有点麻烦&#xff0c;下面我将讲述几种处理流式请求的方式。 1.websocket WebSocket 是处理实时数据流的最佳选择之一&#xff0c;UniApp 提供了原生的 WebSocket 支持&#xff1a; <template><view class"container&…...

代码随想录算法训练营第四十一天|买卖股票专题:121. 买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

动规五部曲牢记于心 1、确定好dp[j]数组&#xff0c;以及下标含义 2、推导出dp[j]公式 3、初始化&#xff0c;关键dp[0][0]、dp[0][1]&#xff0c;第i天&#xff0c;后面的01表示状态&#xff1a;持有、不持有 4、确定遍历顺序&#xff1a; 如果求组合问题&#xff0c;不考虑排…...

AI小白的第七天:必要的数学知识(概率)

概率 Probability 1. 概率的定义 概率是一个介于 0 和 1 之间的数&#xff0c;表示某个事件发生的可能性&#xff1a; 0&#xff1a;事件不可能发生。1&#xff1a;事件必然发生。0 到 1 之间&#xff1a;事件发生的可能性大小。 例如&#xff0c;掷一枚公平的硬币&#xf…...

[Windows] 图吧工具箱

[Windows] 图吧工具箱 链接&#xff1a;https://pan.xunlei.com/s/VOMCXYDix3pvwdkU7w7bfVsDA1?pwdk8v5# DIY爱好者的必备工具...

Docker镜像迁移方案

Docker镜像迁移方案 文章目录 Docker镜像迁移方案一&#xff1a;背景二&#xff1a;操作方式三&#xff1a;异常原因参考&#xff1a; 一&#xff1a;背景 比如机器上已经有先有的容器&#xff0c;但是docker pull的时候是失败的二&#xff1a;操作方式 1、停止正在运行的容器…...

1264. 动态求连续区间和-acwing -树状数组

原题链接&#xff1a;1264. 动态求连续区间和 - AcWing题库 给定 n 个数组成的一个数列&#xff0c;规定有两种操作&#xff0c;一是修改某个元素&#xff0c;二是求子数列 [a,b] 的连续和。 输入格式 第一行包含两个整数 n 和m&#xff0c;分别表示数的个数和操作次数。 第…...

三分钟读懂微服务

一、什么是微服务 微服务&#xff0c;简单来说&#xff0c;就是把一个庞大复杂的软件系统&#xff0c;拆分成一个个小型的、独立的服务模块。打个比方&#xff0c;一个大型商场就如同传统的单体架构软件系统&#xff0c;里面所有的店铺、设施都紧密关联在一起。而微服务架构下…...

【AIGC】图片变视频 - SD ComfyUI视频生成

效果图 完整过程 SD ComfyUI 下载 下载 https://pan.quark.cn/s/64b808baa960 解压密码&#xff1a;bilibili-秋葉aaaki 完整 https://www.bilibili.com/video/BV1Ew411776J/ SD ComfyUI 安装 1.解压 2.将controlnet内部文件复制到 ComfyUI-aki-v1.6\ComfyUI\models\control…...

JVM详解(包括JVM内存模型与GC垃圾回收)

&#x1f4d6;前言&#xff1a; 学会使用Java对于一个程序员是远远不够的。Java语法的掌握只是一部分&#xff0c;另一部分就是需要掌握Java内部的工作原理&#xff0c;从编译到运行&#xff0c;到底是谁在帮我们完成工作的&#xff1f; 接下来着重对Java虚拟机&#xff0c;也就…...

cocos creator 笔记-路边花草

版本&#xff1a;3.8.5 实现目标&#xff1a;给3d道路生成路边景观花草 在场景下创建一个节点&#xff0c;我这里种植两种花草模型&#xff0c;兰花和菊花&#xff0c;所以分别在节点下另创建两个节点&#xff0c;为了静态合批。 1.将花草模型分别拖入场景中&#xff0c;制作…...

在shell脚本内部获取该脚本所在目录的绝对路径

目录 需求描述 方法一&#xff1a;使用 dirname 和 readlink 命令 方法二&#xff1a;使用 BASH_SOURCE 变量 方法三&#xff1a;仅使用纯 Bash 实现 需求描述 工作中经常有这样情况&#xff0c;需要在脚本内部获取该脚本自己所在目录的绝对路径。 假如有一个脚本/a/b/c/…...

Qt 线程类

线程类 这些类与线程应用程序相关。 Concurrent Filter and Filter-Reduce 并行地从序列中选择值并组合它们 Concurrent Map and Map-Reduce 并行地从序列中转换值并组合它们 Concurrent Run 在单独线程中运行任务的简单方法 Concurrent Task 在独立线程中运行任务的可…...