首页 最新 热门 推荐

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

鸿蒙ACE-V1状态分析@Link

  • 24-12-10 09:06
  • 4402
  • 10723
juejin.cn

@Link装饰器:父子双向同步

developer.huawei.com/consumer/cn…

初始化规则图示

image.png

框架行为

@Link装饰的变量和其所属的自定义组件共享生命周期。

为了了解@Link变量初始化和更新机制,有必要先了解父组件和拥有@Link变量的子组件的关系,初始渲染和双向更新的流程(以父组件为@State为例)。

  1. 初始渲染:执行父组件的build()函数后将创建子组件的新实例。初始化过程如下:

    1. 必须指定父组件中的@State变量,用于初始化子组件的@Link变量。子组件的@Link变量值与其父组件的数据源变量保持同步(双向数据同步)。
    2. 父组件的@State状态变量包装类通过构造函数传给子组件,子组件的@Link包装类拿到父组件的@State的状态变量后,将当前@Link包装类this指针注册给父组件的@State变量。
  2. @Link的数据源的更新:即父组件中状态变量更新,引起相关子组件的@Link的更新。处理步骤:

    1. 通过初始渲染的步骤可知,子组件@Link包装类把当前this指针注册给父组件。父组件@State变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(比如@Link包装类) 。
    2. 通知@Link包装类更新后,子组件中所有依赖@Link状态变量的系统组件(elementId)都会被通知更新。以此实现父组件对子组件的状态数据同步。
  3. @Link的更新:当子组件中@Link更新后,处理步骤如下(以父组件为@State为例):

    1. @Link更新后,调用父组件的@State包装类的set方法,将更新后的数值同步回父组件。
    2. 子组件@Link和父组件@State分别遍历依赖的系统组件,进行对应的UI的更新。以此实现子组件@Link同步回父组件@State。

转换前代码

ts
代码解读
复制代码
/** * * LinkChildCmpt.ets * Created by unravel on 2024/5/3 * @abstract */ import { StateClass, StateInterface } from './StateDemoPage' @Component export struct LinkChildCmpt { // 父组件@State到子组件@Link简单数据类型同步 @Link simpleLink: number // class类型 @Link classLink: StateClass // 从父组件中的@State类对象属性到@Link简单类型的同步 @Link classValueLink: string // interface类型 @Link interfaceLink: StateInterface // 数组类型 @Link arrayLink: StateClass[] // 父组件@State数组项到子组件@Link简单数据类型同步 @Link array0IndexValue: string // 从父组件中的@State数组项到@Link class类型的同步 @Link array0IndexLink: StateClass // 日期类型 @Link dateLink: Date // 装饰Map类型变量 @Link mapLink: Map<number, string> // 装饰Set类型变量 @Link setLink: Set<number> // 支持联合类型实例 @Link unionLink: number | undefined build() { Column() { Text(`@Link simpleLink: ${this.simpleLink}`) Text(`@Link classLink: ${this.classLink.value}`) Text(`@Link classValueLink: ${this.classValueLink}`) Text(`@Link interfaceLink: ${this.interfaceLink.value}`) Text(`@Link arrayLink: ${this.arrayLink.map(item => item.value).join(',')}`) Text(`@Link array0IndexValue: ${this.array0IndexValue}`) Text(`@Link array0IndexLink: ${this.array0IndexLink.value}`) Text(`@Link dateLink: ${this.dateLink}`) Text(`@Link mapLink: ${Array.from(this.mapLink).map((kv: [number, string]) => `${kv[0]}:${kv[1]}`).join(',')}`) Text(`@Link setLink: ${Array.from(this.setLink).join(',')}`) Text(`@Link unionLink: ${this.unionLink}`) } } }

转换后代码

ts
代码解读
复制代码
if (!("finalizeConstruction" in ViewPU.prototype)) { Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { }); } interface LinkChildCmpt_Params { simpleLink?: number; classLink?: StateClass; classValueLink?: string; interfaceLink?: StateInterface; arrayLink?: StateClass[]; array0IndexValue?: string; array0IndexLink?: StateClass; dateLink?: Date; mapLink?: Map<number, string>; setLink?: Set<number>; unionLink?: number | undefined; } import type { StateClass, StateInterface } from './StateDemoPage'; export class LinkChildCmpt extends ViewPU { constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) { super(parent, __localStorage, elmtId, extraInfo); if (typeof paramsLambda === "function") { this.paramsGenerator_ = paramsLambda; } this.__simpleLink = new SynchedPropertySimpleTwoWayPU(params.simpleLink, this, "simpleLink"); this.__classLink = new SynchedPropertyObjectTwoWayPU(params.classLink, this, "classLink"); this.__classValueLink = new SynchedPropertySimpleTwoWayPU(params.classValueLink, this, "classValueLink"); this.__interfaceLink = new SynchedPropertyObjectTwoWayPU(params.interfaceLink, this, "interfaceLink"); this.__arrayLink = new SynchedPropertyObjectTwoWayPU(params.arrayLink, this, "arrayLink"); this.__array0IndexValue = new SynchedPropertySimpleTwoWayPU(params.array0IndexValue, this, "array0IndexValue"); this.__array0IndexLink = new SynchedPropertyObjectTwoWayPU(params.array0IndexLink, this, "array0IndexLink"); this.__dateLink = new SynchedPropertyObjectTwoWayPU(params.dateLink, this, "dateLink"); this.__mapLink = new SynchedPropertyObjectTwoWayPU(params.mapLink, this, "mapLink"); this.__setLink = new SynchedPropertyObjectTwoWayPU(params.setLink, this, "setLink"); this.__unionLink = new SynchedPropertyObjectTwoWayPU(params.unionLink, this, "unionLink"); this.setInitiallyProvidedValue(params); this.finalizeConstruction(); } setInitiallyProvidedValue(params: LinkChildCmpt_Params) { } updateStateVars(params: LinkChildCmpt_Params) { } purgeVariableDependenciesOnElmtId(rmElmtId) { this.__simpleLink.purgeDependencyOnElmtId(rmElmtId); this.__classLink.purgeDependencyOnElmtId(rmElmtId); this.__classValueLink.purgeDependencyOnElmtId(rmElmtId); this.__interfaceLink.purgeDependencyOnElmtId(rmElmtId); this.__arrayLink.purgeDependencyOnElmtId(rmElmtId); this.__array0IndexValue.purgeDependencyOnElmtId(rmElmtId); this.__array0IndexLink.purgeDependencyOnElmtId(rmElmtId); this.__dateLink.purgeDependencyOnElmtId(rmElmtId); this.__mapLink.purgeDependencyOnElmtId(rmElmtId); this.__setLink.purgeDependencyOnElmtId(rmElmtId); this.__unionLink.purgeDependencyOnElmtId(rmElmtId); } aboutToBeDeleted() { this.__simpleLink.aboutToBeDeleted(); this.__classLink.aboutToBeDeleted(); this.__classValueLink.aboutToBeDeleted(); this.__interfaceLink.aboutToBeDeleted(); this.__arrayLink.aboutToBeDeleted(); this.__array0IndexValue.aboutToBeDeleted(); this.__array0IndexLink.aboutToBeDeleted(); this.__dateLink.aboutToBeDeleted(); this.__mapLink.aboutToBeDeleted(); this.__setLink.aboutToBeDeleted(); this.__unionLink.aboutToBeDeleted(); SubscriberManager.Get().delete(this.id__()); this.aboutToBeDeletedInternal(); } // 父组件@State到子组件@Link简单数据类型同步 private __simpleLink: SynchedPropertySimpleTwoWayPU<number // class类型 >; get simpleLink() { return this.__simpleLink.get(); } set simpleLink(newValue: number) { this.__simpleLink.set(newValue); } // class类型 private __classLink: SynchedPropertySimpleOneWayPU<StateClass // 从父组件中的@State类对象属性到@Link简单类型的同步 >; get classLink() { return this.__classLink.get(); } set classLink(newValue: StateClass) { this.__classLink.set(newValue); } // 从父组件中的@State类对象属性到@Link简单类型的同步 private __classValueLink: SynchedPropertySimpleTwoWayPU<string // interface类型 >; get classValueLink() { return this.__classValueLink.get(); } set classValueLink(newValue: string) { this.__classValueLink.set(newValue); } // interface类型 private __interfaceLink: SynchedPropertySimpleOneWayPU<StateInterface // 数组类型 >; get interfaceLink() { return this.__interfaceLink.get(); } set interfaceLink(newValue: StateInterface) { this.__interfaceLink.set(newValue); } // 数组类型 private __arrayLink: SynchedPropertySimpleOneWayPU<StateClass[] // 父组件@State数组项到子组件@Link简单数据类型同步 >; get arrayLink() { return this.__arrayLink.get(); } set arrayLink(newValue: StateClass[]) { this.__arrayLink.set(newValue); } // 父组件@State数组项到子组件@Link简单数据类型同步 private __array0IndexValue: SynchedPropertySimpleTwoWayPU<string // 从父组件中的@State数组项到@Link class类型的同步 >; get array0IndexValue() { return this.__array0IndexValue.get(); } set array0IndexValue(newValue: string) { this.__array0IndexValue.set(newValue); } // 从父组件中的@State数组项到@Link class类型的同步 private __array0IndexLink: SynchedPropertySimpleOneWayPU<StateClass // 日期类型 >; get array0IndexLink() { return this.__array0IndexLink.get(); } set array0IndexLink(newValue: StateClass) { this.__array0IndexLink.set(newValue); } // 日期类型 private __dateLink: SynchedPropertySimpleOneWayPU<Date // 装饰Map类型变量 >; get dateLink() { return this.__dateLink.get(); } set dateLink(newValue: Date) { this.__dateLink.set(newValue); } // 装饰Map类型变量 private __mapLink: SynchedPropertySimpleOneWayPU<Map<number, string> // 装饰Set类型变量 >; get mapLink() { return this.__mapLink.get(); } set mapLink(newValue: Map<number, string>) { this.__mapLink.set(newValue); } // 装饰Set类型变量 private __setLink: SynchedPropertySimpleOneWayPU<Set<number> // 支持联合类型实例 >; get setLink() { return this.__setLink.get(); } set setLink(newValue: Set<number>) { this.__setLink.set(newValue); } // 支持联合类型实例 private __unionLink: SynchedPropertySimpleOneWayPU<number | undefined>; get unionLink() { return this.__unionLink.get(); } set unionLink(newValue: number | undefined) { this.__unionLink.set(newValue); } initialRender() { this.observeComponentCreation2((elmtId, isInitialRender) => { Column.create(); }, Column); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link simpleLink: ${this.simpleLink}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link classLink: ${this.classLink.value}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link classValueLink: ${this.classValueLink}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link interfaceLink: ${this.interfaceLink.value}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link arrayLink: ${this.arrayLink.map(item => item.value).join(',')}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link array0IndexValue: ${this.array0IndexValue}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link array0IndexLink: ${this.array0IndexLink.value}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link dateLink: ${this.dateLink}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link mapLink: ${Array.from(ObservedObject.GetRawObject(this.mapLink)).map((kv: [ number, string ]) => `${kv[0]}:${kv[1]}`).join(',')}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link setLink: ${Array.from(ObservedObject.GetRawObject(this.setLink)).join(',')}`); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create(`@Link unionLink: ${this.unionLink}`); }, Text); Text.pop(); Column.pop(); } rerender() { this.updateDirtyElements(); } }

@Link

转换前后

转换成TS之后,和@State的操作类似。

  1. 将原有属性重写为getter和setter
  2. 声明一个以双下划线开头的私有属性,在getter和setter里访问私有属性的get和set方法

image.png

初始化

  1. @Link状态变量转换成TS代码之后对应两个不同的类

  2. SynchedPropertySimpleTwoWayPU

    由简单类型转换而来,不管这个简单类型是否是由父组件中状态变量的属性传递而来,还是基本类型传递而来。只要声明的时候是简单类型,就会生成 SynchedPropertySimpleTwoWayPU

  3. SynchedPropertyObjectTwoWayPU

由非简单类型转换而来

image.png

传递

组件通过命名参数机制,将包装的@State状态对象传递过去了,即实际存储值的ObservedPropertyPU对象,在这里就是__simpleState等

image.png

小结 见 框架行为 1.b.

SynchedPropertyTwoWayPU

SynchedPropertySimpleTwoWayPU和SynchedPropertyObjectTwoWayPU 是SynchedPropertyTwoWayPU的子类

image.png

至于怎么区分的,我们可以在gitee.com/openharmony…里找到代码

image.png

image.png

判断逻辑和@State很类似,可以参考 鸿蒙ACE-状态分析@State  ObservedPropertySimplePU、ObservedPropertyObjectPU 部分

结论:isBasicType里面判断,如果是string、boolean、number、enum、bigin以及他们的包装类String、Boolean、Number等都是基础类型

关联UI

SynchedPropertyTwoWayPU

SynchedPropertyTwoWayPU继承自ObservedPropertyAbstractPU,在constructor的时候将视图和属性传入了父类ObservedPropertyAbstractPU

image.png

ObservedPropertyAbstractPU

如果传入的subscriber是视图就通过owningView_持有,其他情况下放入到subscriberRefs_中

image.png

之后的逻辑就和@State关联UI很相似,可以参考 鸿蒙ACE-状态分析@State  ObservedPropertyPU 怎么关联UI? 部分

结论:状态变量创建的时候会将视图this传进去,在状态变量对象内部通过owningView持有了视图实例

关联使用状态变量的UI

image.png

get方法里调用了recordPropertyDependentUpdate, 这部分可以查看 鸿蒙ACE-状态分析@State

更新UI

@Link 更改时,数据源也更改(set方法)

SynchedPropertyTwoWayPU

public set(newValue: C): void

set方法和@State的set方法很相似,参考Done-鸿蒙ACE-状态分析@State ObservedPropertyPU 怎么更新UI? 部分

同时我们看到设置状态值的时候调用了setObject

image.png

private setObject(newValue: C): void

setObject内部调用了source_.set。调用source_.set之后的流程就和@Prop很相似了,可以参考 鸿蒙ACE-状态分析@Prop source_.set 流程

image.png

setObject最终会导致本类的syncPeerHasChanged调用。由于上一步的notifyPropertyHasChangePU也会最终调用syncPeerHasChanged。所以上一步设置了一个标记位changeNotificationIsOngoing_

防止重复刷新调用

public syncPeerHasChanged(eventSource: ObservedPropertyAbstractPU): void

可以看到是有changeNotificationIsOngoing_的标记位用于防止死循环的

image.png

source_来源

SynchedPropertyTwoWayPU

constructor(source: ObservedPropertyObjectAbstract, owningChildView: IPropertySubscriber, thisPropertyName: PropertyInfo)

我们知道@Prop对应类的constructor内部会把装饰的值包装成一个  ObservedPropertyObjectAbstract

同样的,我们看下@Link里面的source_是怎么来的

image.png

小结:见框架行为 3.

数据源更改时,@Link状态变量怎么更新?

我们看下this.source_所在类的set方法。上面我们知道@Link包装对象被添加到了source的subscriber里面,我们关注下这个变量

ObservedPropertyAbstractPU

public addSubscriber(subscriber: ISinglePropertyChangeSubscriber):void

我们看到addSubscriber把subscriber添加到了两个集合中。一个是SubscriberManager map结构一个是subscriberRefs_ set结构

image.png

subscriberRefs_ 是一个Set集合

image.png

ObservedPropertyPU set

因为@Link的数据源是一个ObservedPropertyPU,所以我们可以看下这个里面的set方法

参考 鸿蒙ACE-状态分析@State set章节,我们知道最终调用到了notifyPropertyHasChangedPU、notifyTrackedObjectPropertyHasChanged

image.png

我们能够看到最终也是调用了subscriber的syncPeerHasChanged。这个subscriber就是本类,所以又回到了上面分析的 syncPeerHasChanged 章节

小结:见框架行为 1. 和 2.

总结

  1. @Link状态变量和@State类似,在编译后,原有变量被重写成getter和setter,同时声明一个私有的变量用于存储原有变量
  2. @Link内实际的存储是source_,source_指向父组件的状态变量包装类,所有的观察都是基于source_,所以@Link也只能观测一层属性的访问
  3. 其他的可以参见 框架行为

图示

image.png

  • @Prop 关联使用状态变量的UI

参考资料

  1. gitee.com/openharmony…
  2. 声明式范式的语法编译转换,语法验证 https://gitee.com/openharmony/developtools_ace_ets2bundle
注:本文转载自juejin.cn的HarderCoder的文章"https://juejin.cn/post/7418118194340986899"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

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

分类栏目

后端 (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)

热门文章

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