自学内容网 自学内容网

HarmonyOS第七章:应用状态共享(PersistentStorage、LocalStorage、AppStorage)

🎉 博客主页:【剑九_六千里-CSDN博客】【剑九_六千里-掘金社区
🎨 上一篇文章:【HarmonyOS第六章:组件状态共享(父子组件传参、多层级组件传参、@Watch监听状态变化、@Observed与@ObjectLink、多层嵌套数据更新)
🎠 系列专栏:【HarmonyOS系列
💖 感谢大家点赞👍收藏⭐评论✍

在这里插入图片描述

在这里插入图片描述

1. PersistentStorage

PersistentStorage 允许将选定的 AppStorage 属性保留在设备磁盘上,以便在应用程序关闭后仍然保持持久化。以下是关于PersistentStorage 的一些细节和注意事项:

  • UI 和业务逻辑不应直接访问 PersistentStorage 中的属性,所有属性访问都应通过 AppStorage 进行。任何在 AppStorage 中的更改都会自动同步到 PersistentStorage
  • PersistentStorage 支持存储简单类型数据,如数字(number)、字符串(string)、布尔(boolean)、枚举(enum)等。
  • 如果需要存储对象类型的数据,可以将其转换为 JSON 字符串后再存储。
  • 注意,持久化变量最好是小于2KB的数据。如果开发者需要存储大量的数据,建议使用数据库API来进行管理和存储。

1.1. 简单数据类型的持久化,获取和修改

1.1.1. 语法

// 1. 通过 PersistentStorage.persistProp() 定义要存储的数据
// 参数一:存储的属性;参数二:存储的值
PersistentStorage.persistProp("xxx", xxx)

// 2. 通过 @StorageProp() 或 @StorageLink() 接收数据
@StorageProp("xxx")
@StorageLink("xxx")

// 3. 接收数据
xxx: number = 0;

// 4. 通过 this.xxx 使用数据
this.xxx 

1.1.2. 使用示例

在这里插入图片描述

使用 PersistentStorage 存储数据,使用 @StorageLink@StorageLink 接收数据,同时数据支持修改:

// PersistentStorage 写入磁盘-app关闭数据依然存在,持久化存储
// 存储简单数据类型:number string boolean等等
// 存储负载数据类型:array object function
PersistentStorage.PersistProp("num",100)

@Entry
@Component
struct Index {
  @StorageLink("num") // 获取数据,单向数据流,只是组件内可以改变数据,并不会写入 PersistentStorage
  // @StorageLink("num") // 获取数据,双向数据流,本地修改会同步写入到 PersistentStorage
  num:number=0 // 如果未存储,默认初始值
   build() {
    Column({space:10}) {
      Text(`${this.num}`)
      Button("修改age").onClick(()=>{
        this.num++
      })
    }.width('100%')
    .height('100%')
  }
}

1.2. 复杂数据类型的持久化,获取和修改

1.2.1. 基本使用

在这里插入图片描述

  • 注意:存储复杂类型数据时,value 必须是json
// 注意:存储复杂类型数据时,value 必须是json
PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {
  name: string;
  age: number;
}

@Entry
@Component
struct Index {
  @StorageLink("user") // 获取数据 @StorageLink("user") 或 @StorageProp("user")
  userInfo: string = "{}" // 默认值
  @State user: User = JSON.parse(this.userInfo); // 将接收到的json转成object

  build() {
    Column() {
      Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据
      Button("修改Age")
        .onClick(() => {
          this.user.age++;
        })
    }
      .width("100%")
      .height("100%")
  }
}

1.2.2. 使用 AppStorage.get() 获取数据,AppStorage.set()写入数据

这个例子中使用 @StorageLink("user") 获取数据,可以实现需求,同时我们也可以使用 AppStorage.get() 来获取数据:
在这里插入图片描述

// 注意:存储复杂类型数据时,value 必须是json
PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {
  name: string;
  age: number;
}

@Entry
@Component
struct Index {
  @StorageLink("user")
  userInfo: string = "{}"
  @State user: User = JSON.parse(this.userInfo); // 将接收到的json转成object

  build() {
    Column() {
      Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据
      Button("修改Age").onClick(() => {
        this.user.age++;
      })

      Button("获取user").onClick(() => {
        const res = AppStorage.get<string>("user") // 获取到的是原数据
        console.log(res)
      })
    }
      .width("100%")
      .height("100%")
  }
}

此时点击修改Age按钮,可以发现age被改变了,但 AppStorage.get() 获取到的是改变前的数据,此时可以通过 AppStorage.set() 重新设置数据 :
在这里插入图片描述

// 注意:存储复杂类型数据时,value 必须是json
PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {
  name: string;
  age: number;
}

@Entry
@Component
struct Index {
  @StorageLink("user")
  userInfo: string = "{}"
  @State user: User = JSON.parse(this.userInfo); // 将接收到的json转成object

  build() {
    Column() {
      Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据
      Button("修改Age").onClick(() => {
        this.user.age++;
        AppStorage.set<string>("user", JSON.stringify(this.user)); // 将修改后的数据重新存储
      })

      Button("获取user").onClick(() => {
        const res = AppStorage.get<string>("user")
        console.log(res)
      })
    }
      .width("100%")
      .height("100%")
  }
}

1.2.3. 使用 link 写入/获取数据

在这里插入图片描述

// 注意:存储复杂类型数据时,value 必须是json

PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {
  name: string;
  age: number;
}

@Entry
@Component
struct Index {
  @StorageLink("user")
  @Watch("update")
  userInfo: string = "{}"
  @State user: User = JSON.parse(this.userInfo); // 将接收到的json转成object
  update() {
    this.user = JSON.parse(this.userInfo)
  }

  build() {
    Column() {
      Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据
      Button("修改Age").onClick(() => {
        this.user.age++;
        // 将修改后的数据重新存储
        AppStorage.set<string>("user", JSON.stringify(this.user));
      })

      Button("AppStorage.get获取user").onClick(() => {
        // 获取数据
        const res = AppStorage.get<string>("user")
        console.log(res)
      })

      Button("Link 方式 获取/写入user").onClick(() => {
        // 获取数据
        const userLink: SubscribedAbstractProperty<string> = AppStorage.link("user")
        console.log(userLink.get())
        userLink.set(JSON.stringify({name: "李四", age: 21}))
      })
    }
      .width("100%")
      .height("100%")
  }
}

1.3. 在其它页面获取存储的数据

测试步骤如下:

  • 修改主页面 age;
  • 点击跳转页面,跳转到其它页面;
  • 查看其它页面获取的数据是否正确;
  • 修改其它页面的数据;
  • 返回主页面,查看主页面数据是否同步更新;

通过 router 跳转页面:

// 注意:存储复杂类型数据时,value 必须是json
import router from '@ohos.router'; // 导入路由模块

PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {
  name: string;
  age: number;
}

@Entry
@Component
struct PersistentStorage3 {
  @StorageLink("user")
  @Watch("update")
  userInfo: string = "{}"
  @State user: User = JSON.parse(this.userInfo); // 将接收到的json转成object
  update() {
    this.user = JSON.parse(this.userInfo)
  }

  build() {
    Column() {
      Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据
      Button("修改Age").onClick(() => {
        this.user.age++;
        // 将修改后的数据重新存储
        AppStorage.set<string>("user", JSON.stringify(this.user));
      })

      Button("AppStorage.get获取user").onClick(() => {
        // 获取数据
        const res = AppStorage.get<string>("user")
        console.log(res)
      })

      Button("Link 方式 获取/写入user").onClick(() => {
        // 获取数据
        const userLink: SubscribedAbstractProperty<string> = AppStorage.link("user")
        console.log(userLink.get())
        userLink.set(JSON.stringify({name: "李四", age: 21}))
      })

      Button("跳转页面").onClick(() => {
      // 路由跳转
        router.pushUrl({
          url: "pages/PersistentStorage4"
        })
      })
    }
      .width("100%")
      .height("100%")
  }
}

路由跳转要求页面必须在 src/main/resources/base/profile/main_pages.json 中进行配置:在这里插入图片描述

PersistentStorage3 页面初始数据为 18 :

在这里插入图片描述

点击 PersistentStorage3 修改Age,并点击跳转到 PersistentStorage4 页面,可以看到 PersistentStorage4 页面获取到了更新后的数据:

在这里插入图片描述
PersistentStorage4 页面修改Age:
在这里插入图片描述

返回 PersistentStorage3 页面,可以看到数据也更新了:
在这里插入图片描述
在这里插入图片描述
因此,使用 PersistentStorage.persistProp() 存储的数据,在所有页面中都可以使用并修改。

2. LocalStorage

LocalStorage 是用于页面级的UI状态存储,通过 @Entry 装饰器接收的参数可以在同一页面内共享相同的LocalStorage 实例。此外,LocalStorage 也可以在 UIAbility 内,在不同页面之间共享状态数据。

2.1. 基本使用

2.2. 页面内共享

在这里插入图片描述

2.2.1. 声明

使用 const storage = new LocalStorage({ key: value }) 来创建LocalStorage实例,其中 key 是存储的键名,value 是初始值。

interface User {
  name: string;
  age: number;
}

const user: User = { name: '张三', age: 18 };
const storage = new LocalStorage(user);

2.2.2. 接收

  • @Entry 构造器接收一个参数,该参数是通过 const storage = new LocalStorage(user); 存储的数据
@Entry(storage)
  • 单向数据绑定:使用 @LocalStorageProp('user') 装饰器,可以在组件内对LocalStorage的值进行单向修改,仅在组件内生效。
  • 双向数据绑定:使用 @LocalStorageLink('user') 装饰器,可以实现全局范围内对LocalStorage的值进行双向修改,多个组件可以共享相同的LocalStorage实例。
// @LocalStorageProp("user")
@LocalStorageLink("user")

2.2.3. 完整示例

// 非持久化,只能在一个 UIAbility 中使用
interface User {
  name: string;
  age: number;
}

const user: User = { name: '张三', age: 18 };
const storage = new LocalStorage(user);

@Entry(storage)
@Component
struct Index {
  // @LocalStorageProp("user") // 使用@LocalStorageProp("user")时,修改值,子组件不会同步
  @LocalStorageLink("user") // 使用@LocalStorageLink("user")时,修改值,子组件会同步
  userInfo: User = { name: "李四", age: 18 } // 默认值

  build() {
    Column() {
      Text(`${this.userInfo.name}---${this.userInfo.age}`)
      Button("Index修改age").onClick(() => {
        this.userInfo.age++;
      })
      ChildA()
      ChildB()
    }
    .width('100%')
  }
}

@Component
struct ChildA {
  @LocalStorageProp("user")
  userInfo: User = { name: "Tom", age: 20 }

  build() {
    Column({ space: 10 }) {
      Text(`${this.userInfo.name}---${this.userInfo.age}`)
        .fontColor(Color.White)
      Button("ChildA修改age").onClick(() => {
        // @LocalStorageProp("user") 接收的参数,子组件修改时,父组件不会同步
        this.userInfo.age++
      })
    }.width('100%')
    .height(100)
    .backgroundColor(Color.Blue)
  }
}

@Component
struct ChildB {
  @LocalStorageLink("user")
  userInfo: User = { name: "Tom", age: 20 }

  build() {
    Column({ space: 10 }) {
      Text(`${this.userInfo.name}---${this.userInfo.age}`)
        .fontColor(Color.White)
      Button("ChildB修改age").onClick(() => {
        // @LocalStorageLink("user") 接收的参数,子组件修改时,父组件会同步
        this.userInfo.age++
      })
    }.width('100%')
    .height(100)
    .backgroundColor(Color.Brown)
  }
}

2.3. 不同页面间共享

  • 创建一个 IndexOther.ets 文件
    在这里插入图片描述

  • IndexOther.ets 加入到路由中
    在这里插入图片描述

  • UIAbility中创建LocalStorage:可以在UIAbility中创建LocalStorage实例,并通过 loadContent 方法提供给加载的窗口,以便在页面间共享状态数据。
    在这里插入图片描述

  • 在页面中获取LocalStorage实例:在页面中,可以通过 const storage = LocalStorage.getShared() 来获取LocalStorage的实例。然后,可以通过 @Entry(storage) 将实例传递给页面,以便在页面中使用LocalStorage来共享和管理状态数据。

// Index.ets

import router from "@ohos.router";
interface User {
  name: string;
  age: number;
}
const storage = LocalStorage.getShared();

@Entry(storage)
@Component
struct Index {
  @LocalStorageLink("user")
  userInfo: User = { name: "李四", age: 18 } // 默认值

  build() {
    Column() {
      Text("这是Index页面")
      Text(`${this.userInfo.name}---${this.userInfo.age}`)
      Button("Index修改age").onClick(() => {
        this.userInfo.age++;
      })
      Button("跳转到IndexOther页面").onClick(() => {
        router.pushUrl({
          url: "pages/IndexOther"
        })
      })
    }
    .width('100%')
  }
}


// IndexOther.ets
import router from "@ohos.router";

// 非持久化,只能在一个 UIAbility 中使用
interface UserInfo {
  name: string;
  age: number;
}

const storage = LocalStorage.getShared();

@Entry(storage)
@Component
struct IndexOther {
  @LocalStorageLink("user")
  userInfo: UserInfo = { name: "李四", age: 18 } // 默认值

  build() {
    Column() {
      Text("这是IndexOther页面")
      Text(`${this.userInfo.name}---${this.userInfo.age}`)
      Button("Index修改age").onClick(() => {
        this.userInfo.age++;
      })
      Button("跳转到Index页面").onClick(() => {
        router.pushUrl({
          url: "pages/Index"
        })
      })
    }
    .width('100%')
  }
}

此时不论在哪一个页面修改数据,都会同步:
在这里插入图片描述

2.4. LocalStorage 存储的数据并不会持久化存储

打开模拟机:

在这里插入图片描述
在这里插入图片描述
初始值如下:

在这里插入图片描述
修改数据:

在这里插入图片描述
关闭当前页面:

在这里插入图片描述
再次打开后发现数据已经变成了初始值,因此 LocalStorage 存储的数据并不会持久化存储:

在这里插入图片描述

3. AppStorage

AppStorage 是应用程序级别的全局UI状态存储,与应用程序的进程绑定。它由UI框架在应用程序启动时创建,用于中央存储应用程序的UI状态属性。

3.1. 基础用法

  • 初始化使用:可以使用 AppStorage.SetOrCreate(key, value) 来初始化AppStorage中的数据,其中 key 是存储的键名,value 是初始值。
  • 单向数据绑定:使用 @StorageProp('user') 装饰器,可以在组件内对AppStorage的值进行单向修改,仅在组件内生效。
  • 双向数据绑定:使用 @StorageLink('user') 装饰器,可以实现全局范围内对AppStorage的值进行双向修改,多个组件可以共享相同的AppStorage实例,从而实现全局状态管理。
interface Person {
  name: string;
  age: number;
}

const user: Person = { name: "张三", age: 18 }
AppStorage.setOrCreate<Person>("user", user)

@Entry
@Component
struct Index {
  // @StorageProp("user")
  @StorageLink("user")
  userInfo: Person = { name: "李四", age: 28 } // 默认值

  build() {
    Column() {
      Text(`${this.userInfo.name}---${this.userInfo.age}`)
      Button("修改age").onClick(() => {
        this.userInfo.age++;
      })
    }.width("100%")
    .height("100%")
  }
}

3.2. 组件共享

在这里插入图片描述
子组件中可共享源数据:

interface Person {
  name: string;
  age: number;
}

const user: Person = { name: "张三", age: 18 }
AppStorage.setOrCreate<Person>("user", user)

@Entry
@Component
struct Index {
  // @StorageProp("user")
  @StorageLink("user")
  userInfo: Person = { name: "李四", age: 28 } // 默认值

  build() {
    Column() {
      Text(`${this.userInfo.name}---${this.userInfo.age}`)
      Button("直接修改age").onClick(() => {
        this.userInfo.age++;
      })
      ChildA()
    }.width("100%")
    .height("100%")
  }
}

@Component
struct ChildA {
  @StorageProp("user") // 不会同步
  // @StorageLink("user") // 会同步
  user: Person = { name: "Tom", age: 20 }

  build() {
    Column({ space: 10 }) {
      Text(this.user.name + "----" + this.user.age)
        .fontColor(Color.White)
      Button("ChildA修改age").onClick(() => {
        this.user.age++
      })
    }.width('100%')
    .height(100)
    .backgroundColor(Color.Blue)
  }
}

3.3. set() 及 get() 方法

  • 使用 AppStorage.set<ValueType>(key, value) 可以覆盖AppStorage中的数据,其中 key 是存储的键名,value 是要存储的新值。
  • 使用 AppStorage.get<ValueType>(key) 可以获取AppStorage中存储的数据,其中 ValueType 是数据的类型,key 是存储的键名。
    在这里插入图片描述
interface Person {
  name: string;
  age: number;
}

const user: Person = { name: "张三", age: 18 }
AppStorage.setOrCreate<Person>("user", user)

@Entry
@Component
struct Index {
  // @StorageProp("user")
  @StorageLink("user")
  userInfo: Person = { name: "李四", age: 28 } // 默认值

  build() {
    Column() {
      Text(`${this.userInfo.name}---${this.userInfo.age}`)
      Button("直接修改age").onClick(() => {
        this.userInfo.age++;
      })
      Button("通过set修改age").onClick(() => {
        AppStorage.set<Person>("user", { name: "李四", age: 28 })
      })
      Button("通过get获取user").onClick(() => {
        const user = AppStorage.get<Person>("user")
        console.log(`${user?.name}---${user?.age}`)
      })
    }.width("100%")
    .height("100%")
  }
}

3.4. AppStorage.link(“user”);

  • 使用 const link: SubscribedAbstractProperty<ValueType> = AppStorage.Link(key) 可以创建一个与AppStorage中数据关联的链接,通过这个链接可以修改和获取数据。您可以使用 link.set(value) 来修改数据,使用 link.get() 来获取数据。这个链接允许您在不同组件之间共享数据,并保持数据的同步。

在这里插入图片描述

4. 总结

  • LocalStorage– 一个UIAbility状态(内存–非持久化–非全应用
  • AppStorage– 应用内状态–多UIAbility共享(内存–非持久化-退出App应用 数据消失
  • PersistenStroage–全局持久化状态(写入磁盘–持久化状态-退出App应用 数据不消失

原文地址:https://blog.csdn.net/to_the_Future/article/details/141825857

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!