getTarget接口:获取状态管理框架代理前的原始对象
developer.huawei.com/consumer/cn…
转换前
/**
*
* GetTargetCmp.ets
* Created by unravel on 2024/9/10
* @abstract
*/
import { UIUtils } from '@kit.ArkUI';
@ObservedV2
class ObservedClass {
@Trace name: string = "Tom";
}
let globalObservedObject: ObservedClass = new ObservedClass(); // 不被代理
let globalNumberList: number[] = [1, 2, 3]; // 不被代理
let globalSampleMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]); // 不被代理
let globalSampleSet: Set<number> = new Set([0, 1, 2, 3, 4]); // 不被代理
let globalSampleDate: Date = new Date(); // 不被代理
@ComponentV2
export struct GetTargetCmp {
@Local observedObject: ObservedClass = globalObservedObject; // V2中对象不被代理
@Local numberList: number[] = globalNumberList; // Array类型创建代理
@Local sampleMap: Map<number, string> = globalSampleMap; // Map类型创建代理
@Local sampleSet: Set<number> = globalSampleSet; // Set类型创建代理
@Local sampleDate: Date = globalSampleDate; // Date类型创建代理
build() {
Column() {
Text(`this.observedObject === globalObservedObject ${this.observedObject ===
globalObservedObject}`) // true
Text(`UIUtils.getTarget(this.numberList) === globalNumberList: ${UIUtils.getTarget(this.numberList) ===
globalNumberList}`) // true
Text(`UIUtils.getTarget(this.sampleMap) === globalSampleMAP: ${UIUtils.getTarget(this.sampleMap) ===
globalSampleMap}`) // true
Text(`UIUtils.getTarget(this.sampleSet) === globalSampleSet: ${UIUtils.getTarget(this.sampleSet) ===
globalSampleSet}`) // true
Text(`UIUtils.getTarget(this.sampleDate) === globalSampleDate: ${UIUtils.getTarget(this.sampleDate) ===
globalSampleDate}`) // true
}
}
}
转换后
ComponentV2中转换成了如下代码
if (!("finalizeConstruction" in ViewPU.prototype)) {
Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { });
}
import { UIUtils } from "@ohos:arkui.StateManagement";
@ObservedV2
class ObservedClass {
@Trace
name: string = "Tom";
}
let globalObservedObject: ObservedClass = new ObservedClass(); // 不被代理
let globalNumberList: number[] = [1, 2, 3]; // 不被代理
let globalSampleMap: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]); // 不被代理
let globalSampleSet: Set<number> = new Set([0, 1, 2, 3, 4]); // 不被代理
let globalSampleDate: Date = new Date(); // 不被代理
export class GetTargetCmp extends ViewV2 {
constructor(parent, params, __localStorage, elmtId = -1, paramsLambda, extraInfo) {
super(parent, elmtId, extraInfo);
this.observedObject = globalObservedObject;
this.numberList = globalNumberList;
this.sampleMap = globalSampleMap;
this.sampleSet = globalSampleSet;
this.sampleDate = globalSampleDate;
this.finalizeConstruction();
}
@Local
observedObject: ObservedClass; // V2中对象不被代理
@Local
numberList: number[]; // Array类型创建代理
@Local
sampleMap: Map<number, string>; // Map类型创建代理
@Local
sampleSet: Set<number>; // Set类型创建代理
@Local
sampleDate: Date; // Date类型创建代理
initialRender() {
this.observeComponentCreation2((elmtId, isInitialRender) => {
Column.create();
}, Column);
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`this.observedObject === globalObservedObject ${this.observedObject ===
globalObservedObject}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`UIUtils.getTarget(this.numberList) === globalNumberList: ${UIUtils.getTarget(this.numberList) ===
globalNumberList}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`UIUtils.getTarget(this.sampleMap) === globalSampleMAP: ${UIUtils.getTarget(this.sampleMap) ===
globalSampleMap}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`UIUtils.getTarget(this.sampleSet) === globalSampleSet: ${UIUtils.getTarget(this.sampleSet) ===
globalSampleSet}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`UIUtils.getTarget(this.sampleDate) === globalSampleDate: ${UIUtils.getTarget(this.sampleDate) ===
globalSampleDate}`);
}, Text);
Text.pop();
Column.pop();
}
rerender() {
this.updateDirtyElements();
}
}
如果是ComponentV1,会转换成如下代码
UIUtil.getTarget
可以看到编译过后,UIUtils.getTarget没有任何改变
我们可以从 gitee.com/openharmony… 中看到这个方法的具体实现
代码里根据是否是V1版本的状态变量,进行了区分处理。除此之外,返回传入的对象
V1版本
首先判断是否是一个ObservedObject。这里只有true的时候才会进入。接着调用了 ObservedObject.GetRawObject
ObservedObject.IsObservedObject 判断的是 obj有没有ObservedObject__IS_OBSERVED_OBJECT这个属性
最终我们找到了SubscribableHandler这个类,只要是 ObservedObject__IS_OBSERVED_OBJECT就返回true。
SubscribableHandler这个类其实就是最终状态变量的代理类,状态变化的观察就依靠这个类
obj作为一个状态管理,它也是被SubscribableHandler代理了get和set
同理,我们看到ObservedObject.GetRawObject实际上是读取的obj的__OBSERVED_OBJECT_RAW_OBJECT属性
这个会走到SubscribableHandler的get方法,在这个方法里判断如果是__OBSERVED_OBJECT_RAW_OBJECT属性就把target返回回去
V2版本
V2版本是获取了soruce的ObserveV2.SYMBOL_PROXY_GET_TARGET属性
和V1版本的实现很类似。只不过对于普通对象,V1版本的代理是SubscribableHandle,而V2版本的则是ObjectProxyHandler
小结
- 不管是V1还是V2版本的状态变量,最终都会被一个Proxy进行代理,这样对于这个对象属性的修改和访问就都能监听到了
- UIUtile的getTarget方法,会调用ObservedObject的GetRawObject,并最终调用到上面代理的get方法,在get方法里根据特定的属性判定,返回原有的target