智能客服
你问我答,随时在线为你解决问题
为了实现序列化类时不丢失属性的复杂类型,开发者可以使用@Type装饰器装饰类属性。
@Type的目的是标记类属性,配合PersistenceV2使用,防止序列化时类型信息丢失。在阅读本文档前,建议提前阅读:PersistenceV2。
@Type从API version 12开始支持。
从API version 12开始,该装饰器支持在元服务中使用。
@Type标记类属性,使得类属性序列化时不丢失类型信息,便于类的反序列化。
| @Type装饰器 | 说明 |
|---|---|
| 装饰器参数 | type:类型。 |
| 可装饰的类型 | Object class以及Array、Date、Map、Set等内嵌类型。 |
只能用在@ObservedV2装饰的类中,不能用在自定义组件中。
- class Sample {
- private data: number = 0;
- }
- @ObservedV2
- class Info {
- @Type(Sample)
- @Trace public sample: Sample = new Sample(); // 正确用法
- }
- @Observed
- class Info2 {
- @Type(Sample)
- sample: Sample = new Sample(); // 错误用法,不能用在@Observed装饰的类中,编译时报错
- }
- @ComponentV2
- struct Index {
- @Type(Sample)
- sample: Sample = new Sample(); // 错误用法,不能用在自定义组件中,编译时报错
- build() {
- }
- }
不支持collections.Set、collections.Map等类型。
不支持非built-in类型。如PixelMap、NativePointer等Native类型,以及ArrayList等ArkTS容器类型。
不支持简单类型。如string、number、boolean等。
不支持构造函数含参的类。
- import { PersistenceV2, Type } from '@kit.ArkUI';
-
- @ObservedV2
- class SampleChild {
- @Trace childNumber: number = 1;
- }
-
- @ObservedV2
- class Sample {
- // 对于复杂对象需要@Type修饰,确保反序列化成功,去掉@Type会反序列化值失败。
- @Type(SampleChild)
- // 对于没有初值的类属性,经过@Type修饰后,需要手动保存,否则持久化失败。
- // 无法使用@Type修饰的类属性,必须要有初值才能持久化。
- @Trace sampleChild?: SampleChild = undefined;
- }
-
- @Entry
- @ComponentV2
- struct TestCase {
- @Local sample: Sample = PersistenceV2.connect(Sample, () => new Sample)!;
-
- build() {
- Column() {
- Text('childNumber value:' + this.sample.sampleChild?.childNumber)
- .fontSize(30)
- .margin(10)
- .onClick(() => {
- this.sample.sampleChild = new SampleChild();
- this.sample.sampleChild.childNumber = 2;
- PersistenceV2.save(Sample);
- })
- }
- .width('100%')
- }
- }

@Type装饰Array<T>、Set<T>、Map<string, T>等容器类型的属性时,应传入元素类型T对应的类,不应传入Array<T>等容器泛型。泛型参数在运行时会被擦除,@Type(Array<T>)等同于@Type(Array),@Type(Set<T>)等同于@Type(Set),框架无法从中获知元素类型为T。
| 属性类型 | @Type应传入 | 不应传入 |
|---|---|---|
| Array<T> | T | Array<T>、Array |
| Set<T> | T | Set<T>、Set |
| Map<string, T> | T | Map<string, T>、Map |
当T为基本类型、Date、Array、Set、Map等非自定义类时,框架原生支持反序列化,@Type参数不影响结果。当T为自定义类时,首次运行数据可正常保存,但应用重启从磁盘恢复数据时,反序列化创建空容器实例(如new Array())而非new T(),T的构造函数不执行,T的属性未被初始化。反序列化结果取决于T的属性序列化后的值类型:值为基本类型或对象时被隐式转换为undefined,值为数组时打印Error日志,错误码为140107。具体如下:
| T的属性类型 | 序列化后的值 | 反序列化结果 |
|---|---|---|
| number、string、boolean | 基本类型 | 隐式转换为undefined,无报错 |
| Date | 字符串 | 隐式转换为undefined,无报错 |
| Array、Set、Map | 数组 | 打印Error日志,错误码为140107 |
| 自定义类 | 对象 | 隐式转换为undefined,无报错 |
以下示例中,元素类型ItemModel包含基本类型属性和容器类型属性,使用@Type(Array<ItemModel>)后应用重启将触发上述问题:
- import { PersistenceV2, Type } from '@kit.ArkUI';
-
- @ObservedV2
- class ItemModel {
- @Trace num: number = 1;
- @Trace arr: Array<number> = [1, 2, 3];
- @Trace set: Set<number> = new Set([1, 2, 3]);
- }
-
- @ObservedV2
- class Data {
- @Type(Array<ItemModel>)
- // 错误用法:运行时退化为@Type(Array),传入容器类型而非元素类型
- // 反序列化时创建new Array()而非new ItemModel(),ItemModel的构造函数不执行,num、arr、set属性均未初始化
- // num序列化后为基本类型,反序列化时被隐式转换为undefined;arr、set序列化后为数组,反序列化时打印Error日志,错误码为140107
- // Set<T>、Map<string, T>场景传入@Type(Set<T>)或@Type(Map<string, T>)同理
- @Trace items: Array<ItemModel> = new Array();
- }
-
- @Entry
- @ComponentV2
- struct TestCase {
- @Local data: Data = PersistenceV2.connect(Data, () => new Data())!;
-
- build() {
- Column() {
- Button('push and save')
- .onClick(() => {
- this.data.items.push(new ItemModel());
- // 手动持久化数据到磁盘
- PersistenceV2.save(Data);
- })
- }
- }
- }
上述示例中,首次点击按钮将ItemModel实例存入数组并保存到磁盘后,结束进程,第二次重新启动时,执行反序列化失败,打印如下Error日志:
- FIX THIS APPLICATION ERROR: For PersistenceV2 'Data' key has error, error code: 140107, message: The type of target 'undefined' mismatches the type of source 'object'
正确写法是将@Type参数改为元素类型T对应的类,对Array<T>、Set<T>、Map<string, T>均适用:
- @ObservedV2
- class Data {
- @Type(ItemModel) // 正确用法:传入元素类型ItemModel对应的类
- @Trace items: Array<ItemModel> = new Array();
- }
智能客服
你问我答,随时在线为你解决问题
合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
解决方案
精准高效的一站式服务支持,助力开发者商业成功