目录
应用全局UI状态存储和持久化V2版本
AppStorageV2
connect
remove
keys
示例
使用限制
PersistenceV2
connect
remove
keys
save
notifyOnError
示例
使用限制
@Type
使用限制
应用全局UI状态存储和持久化V2版本
以下实例AppStorageV2、PersistenceV2和装饰器@Type都需要搭配@ComponentV2使用。
AppStorageV2
AppStorageV2是在应用UI启动时会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorageV2将在应用运行过程保留其数据。数据通过唯一的键字符串值访问。
AppStorageV2支持应用的主线程内多个UIAbility实例间的状态共享
connect
用于在AppStorageV2实例中创建键值对数据或者获取实例中key对应的值,返回创建或获取的值(类实例|undefinded)。返回的不为undefined情况下,该值改变,对应AppStorageV2存储中的值也会改变。
AppStorageV2.connect<T extends object>(type: TypeConstructorWithArgs<T>, keyOrDefaultCreator?: string | StorageDefaultCreator<T>, defaultCreator?: StorageDefaultCreator<T>): T | undefined;
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
type | TypeConstructorWithArgs<T> | 是 | 指定的类型,若未指定key,则使用type的name作为key。 |
keyOrDefaultCreator | string | StorageDefaultCreator<T> | 否 | 指定的key,或者是获取默认值的构造器。 |
defaultCreator | StorageDefaultCreator<T> | 否 | 获取默认值的构造器。 |
有4种形式入参:
AppStorageV2.connect(Sample)
1个参数,类名。相当于AppStorageV2.connect(Sample,"Sample")。
AppStorageV2.connect(Sample,"Sample1")
2个参数,类名+字符串。表示获取AppStorageV2中"Sample1"对应的值,该值的类型为Sample,获取不到返回undefined。
AppStorageV2.connect(Sample,()=>new Sample())
2个参数,类名+默认值构造器。相当于AppStorageV2.connect(Sample,"Sample",()=>new Sample)
AppStorageV2.connect(Sample,"Sample2",()=>new Sample())
3个参数,类名+字符串+默认值构造器。先获取AppStorageV2中"Sample2"对应的值,如果获取不到,则通过调用默认值构造器,将结果存入AppStorageV2值中,key为"Sample2"。
注意:使用时,该方法可能返回undefined,故在给@Local等装饰器修饰的变量赋值时需要在最后加上感叹号!,用来避过undefined的类型检测,表示我确认不会返回undefined。
remove
用于删除AppStorageV2实例中指定的键值对数据,返回undefined。
AppStorageV2.remove<T>(keyOrType: string | TypeConstructorWithArgs<T>): void
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
keyOrType | string | TypeConstructorWithArgs<T> | 是 | 需要删除的key;如果指定的是type类型,删除的key为type的name。 |
只有一种入参方式,可以传类名或者字符串。传类名表示直接删除类名对应字符串后的键值对。
注意:删除AppStorageV2中不存在的key会有Warning提示The key to be deleted does not exist。
keys
AppStorageV2.keys(): Array<string>
返回AppStorageV2实例中的所有key(Array<string>)。
示例
Navigation组件跳转页面时,首页不会重复渲染,返回不会重复渲染,pushPathByName会重新渲染新页面,故下例中首页只会渲染一次,每次跳到page2页面都会渲染一个新的。
1.点击Page1 p1、Page2 p2,p1数字会变动,p2不会,由于@Trace只装饰了p1,p2的实际值增加了,但是由于UI没刷新(在第2步中可以看出来)。
2.点击跳转page2,p1、p2的数字都同步过去了,由于都是在AppStorageV2实例中获取的Sample键值对。
3.点击Page2中按钮,在AppStorageV2中创建一个新的键值对Sample1,当前页面p1、p2的值会还原。
4.点击返回,由于首页不会刷新,这时无变化。
5.点击all keys in AppStorage,触发该段文字ui刷新,发现多了一个Sample1的key。
6.点击remove key按钮AppStorageV2中的Sample键值对删除了。
7.点击跳转page2,发现应用直接报错了,这是由于page2页面重新渲染,其中下面代码AppStorageV2.connect(Sample)返回undefined,@Local不能初始化值传入undefined。
@Local prop: Sample = AppStorageV2.connect(Sample)!;
注意:需要在真机环境运行,在预览环境会报错。
Index.ets页面
// Index.ets
import { AppStorageV2 } from '@kit.ArkUI';// 数据中心
@ObservedV2
export class Sample {@Trace p1: number = 0;p2: number = 10;
}@Entry
@ComponentV2
struct Page1 {// 在AppStorageV2中创建一个key为Sample的键值对(如果存在,则返回AppStorageV2中的数据),并且和prop关联@Local prop: Sample = AppStorageV2.connect(Sample,'Sample',()=>new Sample())!;@Local prop1: String = "1"pageStack: NavPathStack = new NavPathStack();fontSize(){console.log("all keys in AppStorage:渲染了一次")return 30}build() {Navigation(this.pageStack) {Column() {Button('Go to page2').onClick(() => {this.pageStack.pushPathByName('Page2', null);})Button('Page1 connect the key Sample').onClick(() => {// 在AppStorageV2中创建一个key为Sample的键值对(如果存在,则返回AppStorageV2中的数据),并且和prop关联this.prop = AppStorageV2.connect(Sample,()=>new Sample())!;})Button('Page1 remove the key Sample').onClick(() => {// 从AppStorageV2中删除后,prop将不会再与key为Sample的值关联AppStorageV2.remove(Sample);})Text(`Page1 p1: ${this.prop.p1}`).fontSize(30).onClick(() => {this.prop.p1++;})Text(`Page1 p2: ${this.prop.p2}`).fontSize(30).onClick(() => {// 页面不刷新,但是p2的值改变了this.prop.p2++;})// 获取当前AppStorageV2里面的所有keyText(`${this.prop1}all keys in AppStorage: ${AppStorageV2.keys()}`).fontSize(this.fontSize()).onClick(() => {// 页面不刷新,但是p2的值改变了this.prop1 = this.prop1+'1'})}}}
}
Index2.ets页面
// Page2.ets
import { AppStorageV2 } from '@kit.ArkUI';
import { Sample } from './Index';@Builder
export function Page2Builder() {Page2()
}@ComponentV2
struct Page2 {// 在AppStorageV2中创建一个key为Sample的键值对(如果存在,则返回AppStorageV2中的数据),并且和prop关联@Local prop: Sample = AppStorageV2.connect(Sample)!;pathStack: NavPathStack = new NavPathStack();fontSize(){console.log("渲染了一次11")return 30}build() {NavDestination() {Column() {Button('Page2 connect the key Sample1').onClick(() => {// 在AppStorageV2中创建一个key为Sample1的键值对(如果存在,则返回AppStorageV2中的数据),并且和prop关联this.prop = AppStorageV2.connect(Sample,"Sample1",()=>new Sample())!;})Text(`Page2 p1: ${this.prop.p1}`).fontSize(30).onClick(() => {this.prop.p1++;})Text(`Page2 p2: ${this.prop.p2}`).fontSize(this.fontSize()).onClick(() => {// 页面不刷新,但是p2的值改变了;只有重新初始化才会改变this.prop.p2++;})// 获取当前AppStorageV2里面的所有keyText(`all keys in AppStorage: ${AppStorageV2.keys()}`).fontSize(30)}}.onReady((context: NavDestinationContext) => {this.pathStack = context.pathStack;})}
}
使用Navigation组件时,需要添加配置系统路由表文件,先在module.json5中添加:"routerMap": "$profile:route_map",表示使用src/main/resources/base/profile目录下的route_map.json文件作为路由表。故在该目录下创建文件route_map.json。
{"routerMap": [{"name": "Page2","pageSourceFile": "src/main/ets/pages/Index2.ets","buildFunction": "Page2Builder","data": {"description" : "AppStorageV2 example"}}]
}
使用限制
1、需要配合UI使用(UI线程),不能在其他线程使用,如不支持@Sendable。
2、不支持collections.Set、collections.Map等类型。
3、不支持非buildin类型,如PixelMap、NativePointer、ArrayList等Native类型。
PersistenceV2
PersistenceV2是在应用UI启动时会被创建的单例,用于储存持久化的数据。不同于AppStorageV2它会将最新数据储存在设备磁盘上(持久化)。这意味着,应用退出再次启动后,依然能保存之前的数据。
支持应用的主线程内多个UIAbility实例间的状态共享。
注意:由于将数据存储在设备磁盘上,需要将数据进行序列化(数据转为某种固定的格式进行存储,例如全部转为二进制数据)后进行存储。
connect
remove
keys
PersistenceV2类型上继承了AppStorageV2,在AppStorageV2的基础上多实现了save和notifyOnError方法,所以上面3个方法使用同AppStorageV2。
save
PersistenceV2.save<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;
对于与PersistenceV2关联的@ObservedV2对象,该对象的@Trace属性的变化,会触发整个关联对象的自动持久化;非@Trace属性的变化则不会,这时需要通过该方法进行手动持久化。
save | 说明 |
---|---|
参数 | keyOrType:需要手动持久化的key;如果指定的是type类型,key为type的name。 |
返回值 | 无。 |
入参字符串或者类名。传类名表示对类名对应字符串后的键值对进行持久化处理。
notifyOnError
PersistenceV2.notifyOnError(callback: PersistenceErrorCallback | undefined): void;
将数据存入磁盘时,需要对数据进行序列化;当某个key序列化失败时,错误是不可预知的;可调用该接口捕获异常。
notifyOnError | 说明 |
---|---|
参数 | callback:当序列化或者反序列化失败时,执行该回调;若传入undefined,取消该回调。 |
返回值 | 无。 |
示例
注意:需要在真机环境运行,在预览环境会报错。
这里示例和AppStorageV2的示例效果类似。不同在于:
1.退出应用后再次打开应用p1的值不会重置,因为使用的PersistenceV2并被@Trace修饰了,会自动持久化数据。
2.p2的值需要点击Page1 save the key Sample按钮后才会被持久化。这时退出后再打开p2的值会同步。
Index.ets页面
import { Type } from '@kit.ArkUI';
import { PersistenceV2 } from '@kit.ArkUI';// 数据中心
@ObservedV2
class SampleChild {@Trace p1: number = 0;p2: number = 10;
}@ObservedV2
export class Sample {// 对于复杂对象需要@Type修饰,确保序列化成功@Type(SampleChild)@Trace f: SampleChild = new SampleChild();
}
// 接受序列化失败的回调
PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
});@Entry
@ComponentV2
struct Page1 {// 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联// 对于需要换connect对象的prop属性,需要加@Local修饰(不建议对属性换connect的对象)@Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;pageStack: NavPathStack = new NavPathStack();build() {Navigation(this.pageStack) {Column() {Button('Go to page2').onClick(() => {this.pageStack.pushPathByName('Page2', null);})Button('Page1 connect the key Sample').onClick(() => {// 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联// 不建议对prop属性换connect的对象this.prop = PersistenceV2.connect(Sample, 'Sample', () => new Sample())!;})Button('Page1 remove the key Sample').onClick(() => {// 从PersistenceV2中删除后,prop将不会再与key为Sample的值关联PersistenceV2.remove(Sample);})Button('Page1 save the key Sample').onClick(() => {// 如果处于connect状态,持久化key为Sample的键值对PersistenceV2.save("Sample");})Text(`Page1 add 1 to prop.p1: ${this.prop.f.p1}`).fontSize(30).onClick(() => {this.prop.f.p1++;})Text(`Page1 add 1 to prop.p2: ${this.prop.f.p2}`).fontSize(30).onClick(() => {// 页面不刷新,但是p2的值改变了this.prop.f.p2++;})// 获取当前PersistenceV2里面的所有keyText(`all keys in PersistenceV2: ${PersistenceV2.keys()}`).fontSize(30)}}}
}
Index2.ets
import { PersistenceV2 } from '@kit.ArkUI';
import { Sample } from './Index';@Builder
export function Page2Builder() {Page2()
}@ComponentV2
struct Page2 {// 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联// 对于需要换connect对象的prop属性,需要加@Local修饰(不建议对属性换connect的对象)@Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;pathStack: NavPathStack = new NavPathStack();build() {NavDestination() {Column() {Button('Page2 connect the key Sample1').onClick(() => {// 在PersistenceV2中创建一个key为Sample1的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联// 不建议对prop属性换connect的对象this.prop = PersistenceV2.connect(Sample, 'Sample1', () => new Sample())!;})Text(`Page2 add 1 to prop.p1: ${this.prop.f.p1}`).fontSize(30).onClick(() => {this.prop.f.p1++;})Text(`Page2 add 1 to prop.p2: ${this.prop.f.p2}`).fontSize(30).onClick(() => {// 页面不刷新,但是p2的值改变了;只有重新初始化才会改变this.prop.f.p2++;})// 获取当前PersistenceV2里面的所有keyText(`all keys in PersistenceV2: ${PersistenceV2.keys()}`).fontSize(30)}}.onReady((context: NavDestinationContext) => {this.pathStack = context.pathStack;})}
}
使用Navigation组件时,需要添加配置系统路由表文件,先在module.json5中添加:"routerMap": "$profile:route_map",表示使用src/main/resources/base/profile目录下的route_map.json文件作为路由表。故在该目录下创建文件route_map.json。
{"routerMap": [{"name": "Page2","pageSourceFile": "src/main/ets/pages/Index2.ets","buildFunction": "Page2Builder","data": {"description" : "AppStorageV2 example"}}]
}
使用限制
1、需要配合UI使用(UI线程),不能在其他线程使用,如不支持@Sendable。
2、不支持collections.Set、collections.Map等类型。
3、不支持非buildin类型,如PixelMap、NativePointer、ArrayList等Native类型。
4、单个key支持数据大小约8k,过大会导致持久化失败。
5、持久化的数据必须是class对象,不能是容器(如Array、Set、Map),不能是buildin的构造对象(如Date、Number)。
6、不支持循环引用的对象。
7、只有@Trace的数据改变会触发自动持久化,如V1状态变量、@Observed对象、普通数据的改变不会触发持久化。
8、不宜大量持久化数据,可能会导致页面卡顿。
@Type
在持久化数据时,为了实现序列化类时不丢失属性的复杂类型,可以使用@Type装饰器装饰类属性。
@Type装饰器 | 说明 |
---|---|
装饰器参数 | type:类型。 |
可装饰的类型 | Object class以及Array、Date、Map、Set等内嵌类型。 |
class Sample {data: number = 0;
}
// Info会在PersistenceV2中使用。
//@Local prop: Info = PersistenceV2.connect(Info , () => new Info ())!;
@ObservedV2
class Info {@Type(Sample)@Trace sample: Sample = new Sample(); // 正确用法
}
使用限制
1、只能用在@ObservedV2装饰的类中,不能用在自定义组件中。
2、不支持collections.Set、collections.Map等类型。
3、不支持非buildin类型,如PixelMap、NativePointer、ArrayList等Native类型。
4、不支持简单类型,如string、number、boolean等。