赞
踩
前两个小节介绍的LocalStorage和AppStorage都是运行时的内存,但是在应用退出再次启动后,依然能保存选定的结果,是应用开发中十分常见的现象,这就需要用到PersistentStorage。
PersistentStorage是应用程序中的可选单例对象。此对象的作用是持久化存储选定的AppStorage属性,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同。
PersistentStorage将选定的AppStorage属性保留在设备磁盘上。应用程序通过API,以决定哪些AppStorage属性应借助PersistentStorage持久化。UI和业务逻辑不直接访问PersistentStorage中的属性,所有属性访问都是对AppStorage的访问,AppStorage中的更改会自动同步到PersistentStorage。
PersistentStorage和AppStorage中的属性建立双向同步。应用开发通常通过AppStorage访问PersistentStorage,另外还有一些接口可以用于管理持久化属性,但是业务逻辑始终是通过AppStorage获取和设置属性的。
PersistentStorage允许的类型和值有:
number, string, boolean, enum
等简单类型。JSON.stringify()
和JSON.parse()
重构的对象,以及对象的属性方法不支持持久化。set
, clear
, delete
更新Map的值。且更新的值被持久化存储。add
, clear
, delete
更新Set的值。且更新的值被持久化存储。setFullYear
, setMonth
, setDate
, setHours
, setMinutes
, setSeconds
, setMilliseconds
, setTime
, setUTCFullYear
, setUTCMonth
, setUTCDate
, setUTCHours
, setUTCMinutes
, setUTCSeconds
, setUTCMilliseconds
更新Date的属性。且更新的值被持久化存储。undefined
和 null
。PersistentStorage不允许的类型和值有:
持久化数据是一个相对缓慢的操作,应用程序应避免以下情况:
PersistentStorage的持久化变量最好是小于2kb的数据,不要大量的数据持久化,因为PersistentStorage写入磁盘的操作是同步的,大量的数据本地化读写会同步在UI线程中执行,影响UI渲染性能。如果开发者需要存储大量的数据,建议使用数据库api。
PersistentStorage和UI实例相关联,持久化操作需要在UI实例初始化成功后(即 loadContent 传入的回调被调用时)才可以被调用,早于该时机调用会导致持久化失败。
// EntryAbility.ets
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
return;
}
PersistentStorage.persistProp('aProp', 47);
});
}
PersistentStorage.persistProp('aProp', 47);
AppStorage.get<number>('aProp'); // returns 47
或在组件内部定义:
@StorageLink('aProp') aProp: number = 48;
完整代码如下:
PersistentStorage.persistProp('aProp', 47); @Entry @Component struct Index { @State message: string = 'Hello World' @StorageLink('aProp') aProp: number = 48 build() { Row() { Column() { Text(this.message) // 应用退出时会保存当前结果。重新启动后,会显示上一次的保存结果 Text(`${this.aProp}`) .onClick(() => { this.aProp += 1; }) } } } }
新应用安装后首次启动运行:
图1 PersistProp初始化流程
触发点击事件后:
后续启动应用:
该示例为反例。在调用PersistentStorage.persistProp或者persistProps之前使用接口访问AppStorage中的属性是错误的,因为这样的调用顺序会丢失上一次应用程序运行中的属性值:
let aProp = AppStorage.setOrCreate('aProp', 47);
PersistentStorage.persistProp('aProp', 48);
应用在非首次运行时,先执行AppStorage.setOrCreate(‘aProp’, 47):属性“aProp”在AppStorage中创建,其类型为number,其值设置为指定的默认值47。“aProp”是持久化的属性,所以会被写回PersistentStorage磁盘中,PersistentStorage存储的上次退出应用的值丢失。
PersistentStorage.persistProp(‘aProp’, 48):在PersistentStorage中查找到“aProp”,值为刚刚使用AppStorage接口写入的47。
开发者可以先判断是否需要覆盖上一次保存在PersistentStorage中的值,如果需要覆盖,再调用AppStorage的接口进行修改,如果不需要覆盖,则不调用AppStorage的接口。
PersistentStorage.persistProp('aProp', 48);
if (AppStorage.get('aProp') > 50) {
// 如果PersistentStorage存储的值超过50,设置为47
AppStorage.setOrCreate('aProp',47);
}
示例代码在读取PersistentStorage储存的数据后判断“aProp”的值是否大于50,如果大于50的话使用AppStorage的接口设置为47。
PersistentStorage支持联合类型和undefined和null,在下面的示例中,使用persistProp方法初始化"P"为undefined。通过@StorageLink(“P”)绑定变量p,类型为number | undefined | null,点击Button改变P的值,视图会随之刷新。且P的值被持久化存储。
PersistentStorage.persistProp("P", undefined); @Entry @Component struct TestCase6 { @StorageLink("P") p: number | undefined | null = 10; build() { Row() { Column() { Text(this.p + "") .fontSize(50) .fontWeight(FontWeight.Bold) Button("changeToNumber").onClick(() => { this.p = 10; }) Button("changeTo undefined").onClick(() => { this.p = undefined; }) Button("changeTo null").onClick(() => { this.p = null; }) } .width('100%') } .height('100%') } }
在下面的示例中,@StorageLink装饰的persistedDate类型为Date,点击Button改变persistedDate的值,视图会随之刷新。且persistedDate的值被持久化存储。
PersistentStorage.persistProp("persistedDate", new Date()); @Entry @Component struct PersistedDate { @StorageLink("persistedDate") persistedDate: Date = new Date(); updateDate() { this.persistedDate = new Date(); } build() { List() { ListItem() { Column() { Text(`Persisted Date is ${this.persistedDate.toString()}`) .margin(20) Text(`Persisted Date month is ${this.persistedDate.getMonth()}`) .margin(20) Text(`Persisted Date day is ${this.persistedDate.getDay()}`) .margin(20) Text(`Persisted Date time is ${this.persistedDate.toLocaleTimeString()}`) .margin(20) Button() { Text('Update Date') .fontSize(25) .fontWeight(FontWeight.Bold) .fontColor(Color.White) } .type(ButtonType.Capsule) .margin({ top: 20 }) .backgroundColor('#0D9FFB') .width('60%') .height('5%') .onClick(() => { this.updateDate(); }) }.width('100%') } } } }
在下面的示例中,@StorageLink装饰的persistedMapString类型为Map<number, string>,点击Button改变persistedMapString的值,视图会随之刷新。且persistedMapString的值被持久化存储。
PersistentStorage.persistProp("persistedMapString", new Map<number, string>([])); @Entry @Component struct PersistedMap { @StorageLink("persistedMapString") persistedMapString: Map<number, string> = new Map<number, string>([]); persistMapString() { this.persistedMapString = new Map<number, string>([[3, "one"], [6, "two"], [9, "three"]]); } build() { List() { ListItem() { Column() { Text(`Persisted Map String is `) .margin(20) ForEach(Array.from(this.persistedMapString.entries()), (item: [number, string]) => { Text(`${item[0]} ${item[1]}`) }) Button() { Text('Persist Map String') .fontSize(25) .fontWeight(FontWeight.Bold) .fontColor(Color.White) } .type(ButtonType.Capsule) .margin({ top: 20 }) .backgroundColor('#0D9FFB') .width('60%') .height('5%') .onClick(() => { this.persistMapString(); }) }.width('100%') } } } }
在下面的示例中,@StorageLink装饰的persistedSet类型为Set<number>,点击Button改变persistedSet的值,视图会随之刷新。且persistedSet的值被持久化存储。
PersistentStorage.persistProp("persistedSet", new Set<number>([])); @Entry @Component struct PersistedSet { @StorageLink("persistedSet") persistedSet: Set<number> = new Set<number>([]); persistSet() { this.persistedSet = new Set<number>([33, 1, 3]); } clearSet() { this.persistedSet.clear(); } build() { List() { ListItem() { Column() { Text(`Persisted Set is `) .margin(20) ForEach(Array.from(this.persistedSet.entries()), (item: [number, string]) => { Text(`${item[1]}`) }) Button() { Text('Persist Set') .fontSize(25) .fontWeight(FontWeight.Bold) .fontColor(Color.White) } .type(ButtonType.Capsule) .margin({ top: 20 }) .backgroundColor('#0D9FFB') .width('60%') .height('5%') .onClick(() => { this.persistSet(); }) Button() { Text('Persist Clear') .fontSize(25) .fontWeight(FontWeight.Bold) .fontColor(Color.White) } .type(ButtonType.Capsule) .margin({ top: 20 }) .backgroundColor('#0D9FFB') .width('60%') .height('5%') .onClick(() => { this.clearSet(); }) } .width('100%') } } } }
为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr18.cn/F781PH
https://qr18.cn/F781PH
1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。