应用状态管理
帝心个人介绍
帝心:全网首发HarmonyOS4.0教程(哔哩哔哩)创作者。致力于推广鸿蒙教程开发。
LocalStorage:页面级UI状态存储
页面内使用LocalStorage
- 页面内全局初始化
LocalStorage
对象。 - 组件树中使用
@LocalStorageProp("key")
单向数据绑定 - 组件树中使用
@LocalStorageLink("key")
双向数据绑定
单页面使用LocalStorage
效果类似于简单的单双向数据绑定的。即@State
与@Prop
和@Link
区别在于需要在全局初始化LocalStorage
对象。
而LocalStorage
状态存储的价值在于页面间数据联动。此时@State
与@Prop
和@Link
则无法做到。
// 在当前页面初始化 LocalStorage 对象
// 创建新实例并使用给定对象初始化
let person: Record<string, string> = { "userName": 'dxin' }
let storage = new LocalStorage(person)
@Entry(storage)
@Component
struct LocalStorageCurrentPage {
// 页面使用状态变量 和 storage 的 userName 属性进行关联
@LocalStorageProp("userName") lsPropName: string = "细的雅痞"
@LocalStorageLink("userName") lsLinkName: string = "细的雅痞"
// 实时显示 storage 的 userName值
@State storageUsername:string = storage.get('userName') as string
build() {
Column({ space: 30 }) {
// 组件中使用 @LocalStorageProp 状态变量
Column({space:30}) {
Row(){
Text('Prop:' + this.lsPropName).fontSize(20)
Text('storage:' + this.storageUsername).fontSize(20)
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
Button('修改 LocalStorageProp状态变量 的值为【小心心】')
.onClick(() => {
this.lsPropName = '小心心' // 此时页面更新 但是 storage对象 【不变】
this.storageUsername = storage.get('userName') as string
})
Button('修改 storage对象 的值为【帝心】')
.onClick(() => {
storage.set("userName", "帝心") // 此时页面更新 storage对象 【当然会变】
this.storageUsername = storage.get('userName') as string
})
}
.backgroundColor('#ccc')
// 组件中使用 @LocalStorageLink 状态变量
Column({space:30}) {
Row(){
Text('Link:' + this.lsLinkName).fontSize(20)
Text('storage:' + this.storageUsername).fontSize(20)
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
Button('修改 LocalStorageLink状态变量 的值为【小心心】')
.onClick(() => {
this.lsLinkName = '小心心' // 此时页面更新 storage对象 【 被改变 】
this.storageUsername = storage.get('userName') as string
})
Button('修改 storage对象 的值为【帝心】')
.onClick(() => {
storage.set("userName", "帝心") // 此时页面更新 storage对象 【 被改变】
this.storageUsername = storage.get('userName') as string
})
}
.backgroundColor('#ffb77c7c')
// 调用子组件 验证 storage 影响整个组件树的 绑定效果
LocalStorageSon()
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.theme_color'))
}
}
@Component
struct LocalStorageSon {
// 页面使用状态变量 和 storage 的 userName 属性进行关联
@LocalStorageProp("userName") lsPropName: string = "细的雅痞"
@LocalStorageLink("userName") lsLinkName: string = "细的雅痞"
build() {
Column({ space: 30 }) {
Text(this.lsPropName).fontSize(20)
Text(this.lsLinkName).fontSize(20)
}
}
}
页面间使用LocalStorage
- 在多页面所属
UIAbility
中创建LocalStorage
实例,并调用windowStage.loadContent()
时,携带(传参)该实例。 - 在多个UI页面通过
getShared
接口获取通过loadContent
共享的LocalStorage
实例。 - 单双向数据同步同单页面相同,使用
@LocalStorageProp("key")
和@LocalStorageLink("key")
既然提及UIAbility
,或者说Ablity
这个词,你就应该明白,涉及到入口类的执行。
既然涉及到入口类,你就应该想到,预览器能力不够,需要模拟器或者真机。
- 在入口文件中初始化
onWindowStageCreate(windowStage: window.WindowStage): void {
// 初始化 LocalStorage
let personAge:Record<string,number> = {"age":30}
let storage = new LocalStorage(personAge)
windowStage.loadContent('pages/Index', storage,(err) => {
});
}
- 在多页面中获取并使用
官网指导中多页面获取实例时,同名报错(API12IDE5.0.806版本)。遂本示例使用不同名称。
// 获取整个UIAbility共享的【单例】 的 LocalStorage对象
import { router } from '@kit.ArkUI'
let storageA = LocalStorage.getShared()
@Entry(storageA)
@Component
struct LocalStorageA {
//使用状态变量 和 storage 的 age 属性进行关联
@LocalStorageProp("age") lsPropAge: number = 18
@LocalStorageLink("age") lsLinkAge: number = 18
build() {
Column({ space: 30 }) {
Text('同Ability使用LocalStorage 【A】')
.fontSize(30)
Divider()
Button('在A中:@LocalStorageProp 单向修改'+ this.lsPropAge)
.onClick(() => {
this.lsPropAge++
})
Button('在A中:@LocalStorageLink 双向修改'+ this.lsLinkAge)
.onClick(() => {
this.lsLinkAge++
})
Divider()
Button('去B页面瞅一眼')
.onClick(() => {
router.pushUrl({url: "pages/ArkData/LocalStorageB"})
})
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.theme_color'))
}
}
// 获取整个UIAbility共享的【单例】 的 LocalStorage对象
import { router } from '@kit.ArkUI'
let storageB = LocalStorage.getShared()
@Entry(storageB)
@Component
struct LocalStorageB {
@State storageAge:number =storageB.get('age') as number
build() {
Column({ space: 30 }) {
Text('同Ability使用LocalStorage 【B】')
.fontSize(30)
Divider()
Text('B中查看 storageAge:'+this.storageAge).fontSize(30)
Button('back')
.fontSize(30)
.onClick(() => {
router.back()
})
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.theme_color'))
}
}
AppStorage:应用全局的UI状态存储
LocalStorage
是页面级的,通常应用于页面内的数据共享。- 而
AppStorage
是应用级的全局状态共享,还相当于整个应用的“中枢”,AppStorage
是在应用启动的时候会被创建的单例。是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。 - 持久化数据
PersistentStorage
和环境变量Environment
都是通过AppStorage
中转,才可以和UI交互。
使用AppStorage
export default class DxinConstants{
// 。。。
// 收藏诗句 持久化到本地,关键词
static readonly poemArrKey:string = "collectionPoemArr"
}
入口类中初始化数据。此处以数组为例。可以是Class
,number
,boolean
,string
以及这些类型的数组,也支持联合类型
、Date
、Map
、Set
。。。
onWindowStageCreate(windowStage: window.WindowStage): void {
// 存储一个诗词数组
let poemArr: Array<Poem> = []
AppStorage.setOrCreate(DxinConstants.poemArrKey, poemArr)
// ...
}
UI单项同步和双向同步数据
// 双向绑定全局的 存储诗词对象的那个数组
@StorageLink(DxinConstants.poemArrKey) collectionPoemArr: Poem[] = []
// 双向绑定全局的 存储诗词对象的那个数组
// @StorageProp(DxinConstants.poemArrKey) collectionPoemArr: Poem[] = []
PersistentStorage:持久化存储UI状态
PersistentStorage
提供状态变量持久化的能力。应用退出后,再次进入应用,同样保持上次的状态数据。PersistentStorage
使用静态方法persistProp(key,value)
方法持久化存储选定的AppStorage
属性,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同。
注意:
PersistentStorage
和AppStorage
中的属性建立双向同步。PersistentStorage
只能在UI页面内使用。- 不能让
AppStorage.setOrCreate("同名属性","值")
在PersistentStorage.persistProp("同名属性","值")
之前执行,因为会覆盖同名属性持久化过的数据。 PersistentStorage
不要大量的数据持久化,因为PersistentStorage
写入磁盘的操作是同步的,大量的数据本地化读写会同步在UI线程中执行,影响UI渲染性能。如果开发者需要存储大量的数据,建议使用数据库api。
// 持久化
let arr:Array<Poem> = []
PersistentStorage.persistProp(DxinConstants.poemArrKey,arr)
// 双向绑定全局的 存储诗词对象的那个数组
@StorageLink(DxinConstants.poemArrKey) collectionPoemArr: Poem[] = []
// 双向绑定全局的 存储诗词对象的那个数组
// @StorageProp(DxinConstants.poemArrKey) collectionPoemArr: Poem[] = []