【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 就是进行变量判…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...
消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
