【HarmonyOS】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化
【HarmonyOS】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化
前言
之前就Observed和ObjectLink写过一篇讲解博客【HarmonyOS】 多层嵌套对象通过@ObjectLink和@Observed实现渲染更新处理!
其中就@Observe监听类的使用,@ObjectLink进行数据传递进行了讲解。但是其中有些细节没有展开讲,对使用可能会有误解,所以新增一篇详细讲述。
特性明确
对于@ObjectLink和@Observed,我们一般理解为对嵌套对象进行属性监听的一组状态管理标签。
该组标签的诞生是为了解决嵌套对象or数组套数组,数组套对象等等,这种类似数据结构的监听问题,以便于ArkUI框架监听,来实现数据变化,UI渲染。
但是我们使用时,需要明确其作用范围,这样就可以避免一些奇怪的bug。
使用@ObjectLink和@Observed只能监听嵌套后的一级对象属性以及基类属性,无法监听子级及其以下的对象属性。
该结论以我上一篇博客举例,可以点击跳转到该博客,将DEMO示例代码copy下来,边看讲解,边操作DEMO效果更容易理解。
在列表操作数据变化时,我们即操作了一级属性,也操作了二级和三级属性,进行了数值修改。
if判断包裹的select属性为@ObjuectLink直接监听的对象一级属性,如果我们操作了该属性数值变化,就会导致UI刷新。所以if语句块下方的index和content内容变化也能刷新到UI。
该效果可参见前三个Item,点击后就无效果。只有后三个点击后才会有UI刷新。

如此情况如何解决呢?其实嵌套深层次数据结构监听问题,已反馈给华为官方。他们还在开发中,目前V2接口已经可实现嵌套深层次的监听问题。
@ObservedV2装饰器和@Trace装饰器:类属性变化观测,但是新的状态管理标签,还未开发完成,目前不推荐使用,因为不是最终版,随时会变化。
目前该问题的解决方案是:
1.进行二次拆分,继续往下监听对象,这样就可以实现多层数据监听。
但是如果嵌套层数过多,每一层都这样拆分,太过去繁琐。所以我推荐第二种方式,即:
2.对监听层的属性对象,进行操作赋值,不对属性对象之下的属性进行单独赋值。
以我上一篇demo示例代码举例:

当然了,还有一种最简单的方式就是,每次你改变嵌套数据时,监听层有属性也会变化,那UI就会及时刷新。如我DEMO示例一样,正常情况下,我们的Select属性是一定会改变,那UI就会及时刷新。
DEMO示例
以下DEMO示例验证过程【使用@ObjectLink和@Observed只能监听嵌套后的一级对象属性以及基类属性,无法监听子级及其以下的对象属性】

import { ButtonModifier, TextModifier } from '@ohos.arkui.modifier';let NextID: number = 1;
class Bag {public id: number;public size: number;constructor(size: number) {this.id = NextID++;this.size = size;}
}
class BagCopy {public id: number;public size: number;constructor(size: number) {this.id = NextID++;this.size = size;}
}
class Cup {public id: number;public size: number;constructor(size: number) {this.id = NextID++;this.size = size;}
}
class User {public bag: Bag;constructor(bag: Bag) {this.bag = bag;}
}
class Book {public bookName: BookName;constructor(bookName: BookName) {this.bookName = bookName;}
}
class BookName extends BagCopy {public nameSize: number;public cup: Cup;constructor(nameSize: number) {// 调用父类方法对nameSize进行处理super(nameSize);this.nameSize = nameSize;this.cup = new Cup(nameSize);}
}
struct ViewA {label: string = 'ViewA'; bag: Bag;private mTextCommonStyle = new TextCommonStyle();private mButtonCommonStyle = new ButtonCommonStyle();build() {Column() {Text(`ViewA`).attributeModifier(this.mTextCommonStyle)Text(`this.bag.size = ${this.bag.size}`).attributeModifier(this.mTextCommonStyle)Button(`click this.bag.size add 1`).attributeModifier(this.mButtonCommonStyle).onClick(() => {this.bag.size += 1;})}.backgroundColor(Color.Blue)}
}
struct ViewC {label: string = 'ViewC1'; bookName: BookName;private mTextCommonStyle = new TextCommonStyle();private mButtonCommonStyle = new ButtonCommonStyle();build() {Row() {Column() {Text(`ViewC`).attributeModifier(this.mTextCommonStyle)Text(`this.bookName.cup.size = ${this.bookName.cup.size}`).attributeModifier(this.mTextCommonStyle)Button(`click this.bookName.cup.size add 1`).attributeModifier(this.mButtonCommonStyle).onClick(() => {// 当前监听对象的属性,如果是嵌套对象,则该嵌套对象的属性赋值,不会被框架监听到,UI不刷新this.bookName.cup.size += 1;console.log('this.bookName.size:' + this.bookName.size)})Divider().height(5)Text(`this.bookName.size = ${this.bookName.size}`).attributeModifier(this.mTextCommonStyle)Button(`click this.bookName.size add 1`).attributeModifier(this.mButtonCommonStyle).onClick(() => {// 当前监听对象的基类属性被修改,依旧可以被监听到,UI会刷新this.bookName.size += 1;console.log('this.bookName.size:' + this.bookName.size)})}.width(320).backgroundColor(Color.Red)}}
}class TextCommonStyle implements AttributeModifier<TextModifier> {applyNormalAttribute(instance: TextModifier): void {instance.fontColor('#ffffffff').backgroundColor('#ff3d9dba').width(320).height(50).borderRadius(25).margin(10).textAlign(TextAlign.Center)}
}class ButtonCommonStyle implements AttributeModifier<ButtonModifier> {applyNormalAttribute(instance: ButtonModifier): void {instance.width(320).backgroundColor('#ff17a98d').margin(10)}
}
struct ViewB { user: User = new User(new Bag(0)); child: Book = new Book(new BookName(0));build() {Scroll(){Column() {ViewA({ bag: this.user.bag }).width(320)ViewC({ bookName: this.child.bookName }).width(320)Button(`ViewB: this.child.bookName.size add 10`).width(320).backgroundColor('#ff17a98d').margin(10).onClick(() => {this.child.bookName.size += 10console.log('this.child.bookName.size:' + this.child.bookName.size)})Button(`ViewB: this.user.bag = new Bag(10)`).width(320).backgroundColor('#ff17a98d').margin(10).onClick(() => {this.user.bag = new Bag(10);})Button(`ViewB: this.user = new User(new Bag(20))`).width(320).backgroundColor('#ff17a98d').margin(10).onClick(() => {this.user = new User(new Bag(20));})}}}
}
相关文章:
【HarmonyOS】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化
【HarmonyOS】深入理解Observed装饰器和ObjectLink装饰器:嵌套类对象属性变化 前言 之前就Observed和ObjectLink写过一篇讲解博客【HarmonyOS】 多层嵌套对象通过ObjectLink和Observed实现渲染更新处理! 其中就Observe监听类的使用,Object…...
Java笔试面试题AI答之设计模式(1)
文章目录 1. 简述什么是设计模式 ?2. 叙述常见Java设计模式分类 ?3. Java 设计模式的六大原则 ?4. 简述对 MVC 的理解, MVC 有什么优缺点?MVC 的三个核心部分:MVC 的优点:MVC 的缺点:…...
java调用opencv部署到centos7
1、官网下载opencv https://opencv.org/releases/ 2、下载opencv并解压 unzip opencv-3.4.7.zip cd opencv-3.4.7 mkdir build cd build/ 3、安装cmake yum remove cmake -y ; yum install -y gcc gcc-c make automake openssl openssl-devel wget https://cmake.org/files/…...
【python qdrant 向量数据库 完整示例代码】
测试一下python版本的dqrant向量数据库的效果,完整代码如下: 安装库 !pip install qdrant-client>1.1.1 !pip install -U sentence-transformers导入 from qdrant_client import models, QdrantClient from sentence_transformers import SentenceT…...
初识C语言(三)
感兴趣的朋友们可以留个关注,我们共同交流,相互促进学习。 文章目录 前言 八、函数 九、数组 (1)数组的定义 (2)数组的下标和使用 十、操作符 (1)算数操作符 (2ÿ…...
用通义灵码如何快速合理解决遗留代码问题?
本文首先介绍了遗留代码的概念,并对遗留代码进行了分类。针对不同类型的遗留代码,提供了相应的处理策略。此外,本文重点介绍了通义灵码在维护遗留代码过程中能提供哪些支持。 什么是遗留代码 与过时技术相关的代码: 与不再受支持的…...
新书推荐——《Python贝叶斯深度学习》
在过去的十年中,机器学习领域取得了长足的进步,并因此激发了公众的想象力。但我们必须记住,尽管这些算法令人印象深刻,但它们并非完美无缺。本书旨在通过平实的语言介绍如何在深度学习中利用贝叶斯推理,帮助读者掌握开…...
数据结构-3.1.栈的基本概念
一.栈的定义: 栈和线性表的区别:栈只能在表尾一端进行插入或者删除的操作,而线性表可以在任意一个地方进行插入或者删除 二.有关栈的关键术语: 三.栈的基本操作: 1.回顾线性表的基本操作: 2.栈的基本操作&…...
关于 NLP 应用方向与深度训练的核心流程
文章目录 主流应用方向核心流程(5步)1.选定语言模型结构2.收集标注数据3.forward 正向传播4.backward 反向传播5.使用模型预测真实场景 主流应用方向 文本分类文本匹配序列标注生成式任务 核心流程(5步) 基本流程实现的先后顺序…...
linux如何启用ipv6随机地址
简介 在 IPv6 中,临时随机地址(Temporary IPv6 Address)是一种为了提高隐私和安全而设计的功能。通常,默认的 IPv6 地址是基于设备的 MAC 地址生成的,容易导致跟踪和识别设备。启用临时 IPv6 地址可以避免这个问题&am…...
探索 Android DataBinding:实现数据与视图的完美融合
在 Android 开发中,数据与视图的交互一直是一个关键的问题。为了更好地实现数据的展示和更新,Google 推出了 DataBinding 库,它为开发者提供了一种简洁、高效的方式来处理数据与视图之间的绑定关系,大大提高了开发效率和代码的可读…...
Java 编码系列:线程基础与最佳实践
引言 在多任务处理和并发编程中,线程是不可或缺的一部分。Java 提供了丰富的线程管理和并发控制机制,使得开发者可以轻松地实现多线程应用。本文将深入探讨 Java 线程的基础知识,包括 Thread 类、Runnable 接口、Callable 接口以及线程的生命…...
《深度学习》—— ResNet 残差神经网络
文章目录 一、什么是ResNet?二、残差结构(Residual Structure)三、Batch Normalization(BN----批归一化) 一、什么是ResNet? ResNet 网络是在 2015年 由微软实验室中的何凯明等几位大神提出,斩获…...
针对考研的C语言学习(定制化快速掌握重点3)
1.数组常见错误 数组传参实际传递的是数组的起始地址,若在函数中改变数组内容,数组本身也会发生变化 #include<stdio.h> void change_ch(char* str) {str[0] H; } int main() {char ch[] "hello";change_ch(ch);printf("%s\n&q…...
pikachu XXE(XML外部实体注入)通关
靶场:pikachu 环境: 系统:Windows10 服务器:PHPstudy2018 靶场:pikachu 关卡提示说:这是一个接收xml数据的api 常用的Payload 回显 <?xml version"1.0"?> <!DOCTYPE foo [ <!ENTITY …...
shell脚本定时任务通知到钉钉
shell脚本定时任务通知到钉钉 1、背景 前两天看了一下定时任务,垃圾清理、日志相关、系统巡检这些,有的服务器运行就有问题,或者不运行,正好最近在做运维标准重制运维手册,顺便把自动化这块优化一下,所…...
2.4K star的GOT-OCR2.0:端到端OCR 模型
GOT-OCR2.0是一款新一代的光学字符识别(OCR)技术,标志着人工智能在文本识别领域的重大进步。作为一款开源模型,GOT-OCR2.0不仅支持传统的文本和文档识别,还能够处理乐谱、图表以及复杂的数学公式,为用户提供…...
【JavaEE】——线程的安全问题和解决方式
阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!希望本文内容能够帮助到你! 目录 一:问题引入 二:问题深入 1:举例说明 2:图解双线程计算…...
初步认识了解分布式系统
背景认识:我们要学习redis,还是得了解一下什么是分布式。为什么呢?因为redis只有在分布式系统中才能发挥它最大的作用,也就是领域展开,所以接下来我们就简单过一下什么是分布式系统 一些术语认识: &#x…...
react 为什么不能学习 vue3 进行静态节点标记优化性能?
因为 React 使用的是 JSX,而 JSX 本质上就是 JS 语言,是具有非常高的动态的,而 Vue 使用的 template 则是给了足够的约束,比如说 Vue 的 template 里面使用了很多特定的标记来做不同的事情,比如说 v-if 就是进行变量判…...
OpenClaw隐私保护:GLM-4.7-Flash本地处理敏感数据的实践方案
OpenClaw隐私保护:GLM-4.7-Flash本地处理敏感数据的实践方案 1. 为什么需要本地化AI处理敏感数据? 去年我在处理公司财务报告自动化时遇到一个棘手问题:使用云端AI服务需要上传包含客户隐私的Excel文件到第三方服务器。尽管服务商承诺数据安…...
JS知识点汇总(十九)--ajax
1. 说说ajax的原理,以及如何实现? AJAX 全称(Async Javascript and XML) 即异步的 JavaScript 和 XML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更…...
从零开始:在VMware虚拟机中部署Janus-Pro-7B进行开发测试
从零开始:在VMware虚拟机中部署Janus-Pro-7B进行开发测试 想试试最新的AI大模型,但手头没有昂贵的独立GPU服务器?别担心,今天我们就来聊聊一个非常接地气的方案:用你手边的普通电脑,通过VMware虚拟机&…...
如何让鼠标和触控板和平共处:Scroll Reverser实现设备独立控制的效率革命
如何让鼠标和触控板和平共处:Scroll Reverser实现设备独立控制的效率革命 【免费下载链接】Scroll-Reverser Per-device scrolling prefs on macOS. 项目地址: https://gitcode.com/gh_mirrors/sc/Scroll-Reverser 在多设备协同办公成为常态的今天࿰…...
告别重复造轮子,用快马ai一键生成tomcat高效开发工具集与配置模板
今天想和大家分享一个提升Tomcat开发效率的小技巧。作为一个经常和Tomcat打交道的开发者,我发现每次新建项目都要重复写一些基础工具类,特别浪费时间。最近在InsCode(快马)平台上尝试用AI生成了一套可复用的工具集,效果很不错。 数据库连接池…...
CTE、临时表、子查询如何选?
在 SQL Server 等关系型数据库中,处理复杂查询逻辑时,子查询 (Subquery)、临时表 (Temporary Table) 和公共表表达式 (CTE, Common Table Expression) 是三种核心工具。它们各有优劣,选择哪种取决于具体的性能需求、数据规模、代码可读性以及…...
python-flask-djangol框架的膳食营养食谱管理系统
目录需求分析技术选型数据库设计核心功能实现界面设计测试与部署维护与扩展项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作需求分析 膳食营养食谱管理系统需要具备用户管理、食谱管理、营养分析、购物清单生成等功能。系统应支…...
PMOD接口概述
简介 PMOD接口外设模块特点:低频,少量IO引脚。 两种物理规格:6针接口(4IO, 1VCC, 1GND)、12针接口(8IO, 2VCC, 2GND)。 支持的接口协议:SPI、I2C、UART、I2C、H桥、GPIO。 外设模块与主机连接方式:模块直连主机、通过6Pin或12Pin线缆或者12Pin转双6Pin分叉线缆。 外设…...
SystemVerilog内存操作实战:手把手教你实现AXI VIP中的backdoor读写
SystemVerilog内存操作实战:AXI VIP中的backdoor读写技术解析 在硬件验证领域,AXI总线协议因其高性能和灵活性已成为行业标准。验证工程师经常需要与AXI VIP(Verification IP)交互,其中内存操作是最基础也最关键的环节…...
别再让PowerBI报告挤成一团了!用按钮+书签,一个页面搞定趋势和明细分析
PowerBI交互设计进阶:用按钮与书签打造空间魔术 当业务分析报告遇上数据爆炸时代,信息过载与界面拥挤成为每个分析师挥之不去的噩梦。我曾见过某零售企业的季度分析仪表板——12个图表密密麻麻挤在A4纸大小的画布上,趋势线相互缠绕ÿ…...
