【鸿蒙开发】应用状态管理LocalStorage,AppStorage,PersistentStorage

news2025/6/28 8:46:02

 0. 应用状态管理

  • LocalStorage:页面级UI状态存储,通常用于UIAbility内、页面间的状态共享。
  • AppStorage:特殊的单例LocalStorage对象,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储;
  • PersistentStorage:持久化存储UI状态,通常和AppStorage配合使用,选择AppStorage存储的数据写入磁盘,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同;
  • Environment:应用程序运行的设备的环境参数,环境参数会同步到AppStorage中,可以和AppStorage搭配使用。

1. LocalStorage 页面级UI状态存储

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

内存--非持久化--非全应用

1.1 概述

LocalStorage是ArkTS为构建页面级别状态变量提供存储的内存内“数据库”。

  • 应用程序可以创建多个LocalStorage实例,LocalStorage实例可以在页面内共享,也可以通过GetShared接口,实现跨页面、UIAbility实例内共享。
  • 组件树的根节点,即被@Entry装饰的@Component,可以被分配一个LocalStorage实例,此组件的所有子组件实例将自动获得对该LocalStorage实例的访问权限;
  • 被@Component装饰的组件最多可以访问一个LocalStorage实例和AppStorage,未被@Entry装饰的组件不可被独立分配LocalStorage实例,只能接受父组件通过@Entry传递来的LocalStorage实例。一个LocalStorage实例在组件树上可以被分配给多个组件。
  • LocalStorage中的所有属性都是可变的。

应用程序决定LocalStorage对象的生命周期。当应用释放最后一个指向LocalStorage的引用时,比如销毁最后一个自定义组件,LocalStorage将被JS Engine垃圾回收。

LocalStorage提供了两个装饰器:

  • @LocalStorageProp:单向同步关系。
  • @LocalStorageLink:双向同步关系。

1.2 页面内共享

  • 在页面创建LocalStorage实例,const storage = new LocalStorage({ key: value })
  • 把storage实例传入@Entry
  • 单向数据绑定:使用 @LocalStorageProp('user') 装饰器,可以在组件内对LocalStorage的值进行单向修改,仅在组件内生效。
  • 双向数据绑定:使用 @LocalStorageLink('user') 装饰器,可以实现全局范围内对LocalStorage的值进行双向修改,多个组件可以共享相同的LocalStorage实例。

1.3 示例

class Person {
  name?: string
  age?: number
}

const storage: LocalStorage = new LocalStorage({
  user: { name: "lili", age: 18 }
})

@Entry(storage)
@Component
struct Index {
  @LocalStorageProp("user")
  user: Person = { name: "Tom", age: 20 }

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

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

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


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

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

 

1.4 页面间共享

页面间共享LocalStorage实例,请确保在模拟器上进行测试以验证功能是否正常工作

  • 在UIAbility中创建LocalStorage,const storage = new LocalStorage({ key: value })
  • 把storage实例传入到 windowStage.loadContent 方法中
  • 在页面中获取LocalStorage实例, const storage = LocalStorage.GetShared() 
  • 把storage实例传入@Entry

1.5 示例

修改 EntryAbility.ts

import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';

export default class EntryAbility extends UIAbility {
  onCreate(want, launchParam) {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy() {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  storage: LocalStorage = new LocalStorage({
    user: {
      name: "lili", age: 18
    }
  })

  onWindowStageCreate(windowStage: window.WindowStage) {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', this.storage, (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }

  onWindowStageDestroy() {
    // Main window is destroyed, release UI related resources
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground() {
    // Ability has brought to foreground
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground() {
    // Ability has back to background
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

新建 models/index.ets

export class Person {
  name?: string
  age?: number
}

修改 pages/Index.ets

import router from '@ohos.router'
import { Person } from '../models'

const storage = LocalStorage.GetShared()


@Entry(storage)
@Component
struct Index {
  @LocalStorageLink("user")
  user: Person = { name: "Tom", age: 28 }

  build() {
    Column() {
      Text(`${this.user.name}--${this.user.age}`)
      Button("修改age").onClick(() => {
        this.user.age++
      })

      Button("去otherPage").onClick(() => {
        router.pushUrl({
          url: "pages/OtherPage"
        })
      })

    }
    .width('100%')
    .height('100%')
  }
}

 新建页面 OtherPage.ets

import router from '@ohos.router'
import { Person } from '../models'

const storage = LocalStorage.GetShared()

@Entry(storage)
@Component
struct OtherPage {
  @LocalStorageLink("user")
  user: Person = { name: "lisa", age: 38 }

  build() {
    Row() {
      Column() {
        Text(`${this.user.name}--${this.user.age}`)
        Button("修改age").onClick(() => {
          this.user.age++
        })
        Button("返回").onClick(() => {
          router.back()
        })
      }
      .width('100%')
    }
    .height('100%')
  }
}

2. AppStorage 应用全局的UI状态存储

AppStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。

内存--非持久化--应用退出再次启动后 数据消失

2.1 概述

AppStorage是在应用启动的时候会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorage将在应用运行过程保留其属性。属性通过唯一的键字符串值访问。

AppStorage可以和UI组件同步,且可以在应用业务逻辑中被访问。

AppStorage中的属性可以被双向同步,数据可以是存在于本地或远程设备上,并具有不同的功能,比如数据持久化(详见PersistentStorage)。这些数据是通过业务逻辑中实现,与UI解耦,如果希望这些数据在UI中使用,需要用到@StorageProp和@StorageLink。

2.2 从UI内部使用AppStorage

  • 使用 AppStorage.SetOrCreate(key, value) 初始化AppStorage中的数据。
  • 使用 @StorageProp('user') 装饰器,可以在组件内对AppStorage的值进行单向数据绑定。
  • 使用 @StorageLink('user') 装饰器,可以实现全局范围内对AppStorage的值进行双向数据绑定,多个组件可以共享相同的AppStorage实例。

修改 pages/Index.ets

import router from '@ohos.router'
import { Person } from '../models'

AppStorage.SetOrCreate<Person>("user", { name: "lili", age: 18 })

@Entry
@Component
struct Index {
  @StorageLink("user")
  user: Person = { name: "Tom", age: 20 }

  build() {
    Column({ space: 10 }) {
      Text(this.user.name + "----" + this.user.age)
      Button("修改age").onClick(() => {
        this.user.age++
      })
      Button("跳转到TwoPage").onClick(() => {
        router.pushUrl({
          url: "pages/TwoPage"
        })
      })
    }
    .width('100%')
    .height('100%')
  }
}

添加页面 TwoPage.ets

import router from '@ohos.router'
import { Person } from '../models'

@Entry
@Component
struct TwoPage {
  @StorageLink("user")
  user: Person = { name: "Tom", age: 20 }

  build() {
    Column({ space: 10 }) {
      Text(this.user.name + "----" + this.user.age)
      Button("修改age").onClick(() => {
        this.user.age++
      })
      Button("返回Index页面").onClick(() => {
        router.back()
      })

    }.width('100%')
    .height('100%')
  }
}

 

2.3 从应用逻辑使用AppStorage

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

修改 pages/Index.ets 

import promptAction from '@ohos.promptAction'
import { Person } from '../models'

AppStorage.SetOrCreate<Person>("user", { name: "lili", age: 18 })

@Entry
@Component
struct Index {
  @StorageLink("user")
  user: Person = { name: "Tom", age: 20 }

  build() {
    Column({ space: 10 }) {
      Text(this.user.name + "----" + this.user.age)
      Button("修改age").onClick(() => {
        this.user.age++
      })

      Button("获取user信息").onClick(() => {
        const user = AppStorage.Get<Person>("user");
        console.info(user.name)
        promptAction.showToast({
          message: "user.name:" + user.name + " user.age:" + user.age,
          bottom: 20
        })
      })
      Button("覆盖user信息").onClick(() => {
        AppStorage.Set<Person>("user", { name: "Tom", age: 28 });
      })

      Button("通过 Link 覆盖user信息").onClick(() => {
        const userLink: SubscribedAbstractProperty<Person> = AppStorage.Link("user");
        userLink.set({ name: "Jack", age: 38 })
      })

    }
    .width('100%')
    .height('100%')
  }
}

 

3. PersistentStorage 持久化存储UI状态

写入磁盘--持久化状态--应用退出 数据不消失

3.1 概述

PersistentStorage将选定的AppStorage属性保留在设备磁盘上。应用程序通过API,以决定哪些AppStorage属性应借助PersistentStorage持久化。UI和业务逻辑不直接访问PersistentStorage中的属性,所有属性访问都是对AppStorage的访问,AppStorage中的更改会自动同步到PersistentStorage。

3.2 限制条件

PersistentStorage允许的类型和值有:

  • number, string, boolean, enum 等简单类型。
  • 可以被JSON.stringify()和JSON.parse()重构的对象。例如Date, Map, Set等内置类型则不支持,以及对象的属性方法不支持持久化。

PersistentStorage不允许的类型和值有:

  • 不支持嵌套对象(对象数组,对象的属性是对象等)。因为目前框架无法检测AppStorage中嵌套对象(包括数组)值的变化,所以无法写回到PersistentStorage中。
  • 不支持undefined 和 null 。

PersistentStorage的持久化变量最好是小于2kb的数据。

PersistentStorage只能在UI页面内使用,否则将无法持久化数据。

3.3 接口

PersistProp

static PersistProp<T>(key: string, defaultValue: T): void

将AppStorage中key对应的属性持久化到文件中。该接口的调用通常在访问AppStorage之前。

DeleteProp

static DeleteProp(key: string): void

将key对应的属性从PersistentStorage删除,后续AppStorage的操作,对PersistentStorage不会再有影响。

PersistProps

static PersistProps(properties: {key: string, defaultValue: any;}[]): void

行为和PersistProp类似,不同在于可以一次性持久化多个数据,适合在应用启动的时候初始化。

Keys

static Keys(): Array<string>

返回所有持久化属性的key的数组。

3.4 简单数据类型的持久化

PersistentStorage.PersistProp("num", 100)

@Entry
@Component
struct Index {
  @StorageLink("num")
  num: number = 0

  build() {
    Column({ space: 10 }) {
      Text(`${this.num}`)
      Button("修改age").onClick(() => {
        this.num++
      })
    }
    .width('100%')
    .height('100%')
  }
}

 

3.5 复杂数据类型的持久化

修改 pages/Index.ets

import router from '@ohos.router'
import { Person } from '../models'


PersistentStorage.PersistProp("user", '{"name":"lili","age":18}')

@Entry
@Component
struct Index {
  @StorageLink("user")
  @Watch("update")
  userData: string = ""
  @State user: Person = JSON.parse(this.userData)

  update() {
    this.user = JSON.parse(this.userData)
  }

  build() {
    Column() {
      Text(this.user.name + "----" + this.user.age)
      Button("修改age").onClick(() => {
        this.user.age++
        AppStorage.Set<string>("user", JSON.stringify(this.user))
      })
      Button("去其他页面").onClick(() => {
        router.pushUrl({
          url: "pages/OtherPage"
        })
      })

      Button("获取").onClick(() => {
        const user = AppStorage.Get<string>("user")
        console.log(user)
      })

      Button("AppStorage Set 修改1").onClick(() => {
        AppStorage.Set<string>("user", JSON.stringify({ "name": "lisa", "age": 20 }))
      })

      Button("AppStorage Link 修改2").onClick(() => {
        const userLink: SubscribedAbstractProperty<string> = AppStorage.Link("user")
        userLink.set(JSON.stringify({ "name": "jack", "age": 20 }))
      })
    }
    .width("100%")
    .height("100%")
  }
}


添加页面 OtherPage.ets

import router from '@ohos.router'
import { Person } from '../models'


@Entry
@Component
struct OtherPage {
  @StorageLink("user")
  userData: string = ""
  @State user: Person = JSON.parse(this.userData)

  build() {
    Column() {
      Text(this.user.name + "----" + this.user.age)
      Button("修改age").onClick(() => {
        this.user.age++
        AppStorage.Set<string>("user", JSON.stringify(this.user))
      })
      Button("返回Index页面").onClick(() => {
        router.back()
      })
    }
    .width("100%")
    .height("100%")
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1583865.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙HarmonyOS开发实例:【分布式关系型数据库】

介绍 本示例使用[ohos.data.relationalStore]接口和[ohos.distributedDeviceManager] 接口展示了在eTS中分布式关系型数据库的使用&#xff0c;在增、删、改、查的基本操作外&#xff0c;还包括分布式数据库的数据同步同能。 效果预览 使用说明: 启动应用后点击“ ”按钮可…

实验1 eNSP安装与使用

实验1 eNSP安装与使用 一、 原理描述二、 实验目的三、 实验内容四、 实验步骤1.下载并安装eNSP2.eNSP软件界面3.搭建并运行网络拓扑4. Wireshark 捕获分组并分析 一、 原理描述 eNSP&#xff08;Enterprise Network Simulation Platform&#xff09;是由华为提供的免费网络模…

TrollInstallerX官方一键安装巨魔商店

TrollInstallerX是巨魔官方开发的一款一键巨魔商店安装器&#xff0c;完美支持iOS 14.0 – 16.6.1的设备&#xff0c;操作非常简单&#xff0c;TrollInstallerX依然有个小小的限制&#xff0c;部分机型&#xff0c;还是要采用间接安装方法。 一&#xff0c;直接安装方法 通过…

探索进程控制第一弹(进程终止、进程等待)

文章目录 进程创建初识fork函数fork函数返回值fork常规用法fork调用失败的原因 写时拷贝进程终止进程终止是在做什么&#xff1f;进程终止的情况代码跑完&#xff0c;结果正确/不正确代码异常终止 如何终止 进程等待概述进程等待方法wait方法waitpid 进程创建 初识fork函数 在…

C++ 线程库(thread)与锁(mutex)

一.线程库(thread) 1.1 线程类的简单介绍 thread类文档介绍 在C11之前&#xff0c;涉及到多线程问题&#xff0c;都是和平台相关的&#xff0c;比如windows和linux下各有自己的接口&#xff0c;这使得代码的可移植性比较差。C11中最重要的特性就是对线程进行支持了&#xff…

数据结构与算法——字符串暴力匹配

一、字符串的组成 1.数据域&#xff0c;字符串的内容 2.字符串的长度 二、模式匹配-暴力匹配原理 1.两个字符串一个主串一个模式串用两个指针对其进行匹配 2、两个指针所对应的值相同时继续匹配下一个 3、当出现不匹配的情况时&#xff0c;回溯主串的指针到刚开始起点的下一个位…

IP地址定位技术在各领域的作用

IP地址定位是通过确定IP地址的物理位置来定位一个设备的技术&#xff0c;它在现代社会的多个领域中都有着广泛的应用。以下将详细探讨IP地址定位的应用场景&#xff0c;以期对读者有所启发。 首先&#xff0c;在网络安全领域&#xff0c;IP地址定位发挥着至关重要的作用。网络…

业务逻辑漏洞(靶场) fiddler

目录 fiddler简介&#xff1a; 业务逻辑漏洞&#xff1a; fiddler下载 靶场&#xff1a; 实验一 ​编辑实验二&#xff08;ps 更改实验url会变&#xff0c;fiddler没抓到东西看看代理改没改&#xff09; 实验三 实验四 fiddler简介&#xff1a; 一款网络抓包工具&#…

如何丝滑地切换node版本

背景 由于有些比较老的系统&#xff0c;使用的node版本较低&#xff0c;本机装的node版本又比较高&#xff0c;不想降node版本&#xff0c;那么就需要考虑能不能在系统里管理多个node版本呢&#xff1f;由于我使用的操作系统是Mac&#xff0c;下面将主要讲解如何在Mac上快速切…

Tmux 使用笔记

Tmux 是一个终端复用器&#xff08;terminal multiplexer&#xff09;&#xff0c;非常有用&#xff0c;属于常用的开发工具。 本文记录个人使用 Tmux的命令。 1. tmux简介 命令行的典型使用方式是&#xff0c;打开一个终端窗口&#xff0c;连接计算机&#xff0c;在里面输入…

LeetCode-热题100:148. 排序链表

题目描述 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a; head [4,2,1,3] 输出&#xff1a; [1,2,3,4] 示例 2&#xff1a; 输入&#xff1a; head [-1,5,3,4,0] 输出&#xff1a; [-1,0,3,4,5] 示例…

探索未来产业:新技术、新商业、新趋势

引言 随着科技的迅速发展和全球经济的不断变化&#xff0c;未来产业已经成为全球关注的焦点之一。未来产业的兴起不仅代表着新的商业机遇&#xff0c;更是对传统产业模式的颠覆和重构。在这个充满挑战和机遇的时代&#xff0c;我们不得不认真思考未来产业的重要性和前景。 未…

现在软考考什么科目最好?

适合你的学科才是最适合你的学科。 在软考的同一级别&#xff0c;证书的价值差不多。只能说有些学科比较受欢迎&#xff0c;需求量比较大。 中级的系统集成项目管理工程师是最受欢迎的考试科目&#xff0c;其次是软件设计师和网络工程师。由于市场需求大&#xff0c;报考人数也…

gradio简单搭建——关键词匹配筛选【进一步优化】

gradio简单搭建——关键词匹配筛选[进一步优化] 任务回顾新的想法&#xff1a;无效元素筛选界面搭建数据处理与生成过程交互界面展示 任务回顾 在 apply \text{apply} apply方法的使用一节中&#xff0c;简单提到了任务目标&#xff1a;通过关键词的形式&#xff0c;在文本数据…

DNS 各记录类型说明及规则

各记录类型使用目的 记录类型使用目的A 记录将域名指向一个 IP 地址。CNAME 记录将域名指向另一个域名&#xff0c;再由另一个域名提供 IP 地址。MX 记录设置邮箱&#xff0c;让邮箱能收到邮件。NS 记录将子域名交给其他 DNS 服务商解析。AAAA 记录将域名指向一个 IPv6 地址。…

VMware vSphere虚拟化基础管理平台

VMware简介 VMware介绍 官网&#xff1a;https://www.vmware.com/cn.html VMware公司成立于1998年&#xff0c;2003年存储厂商EMC以6.35亿美元收购了VMware&#xff1b;2015年10月&#xff0c;戴尔宣布以670亿美元收购EMC。VMware公司在2018年全年收入79.2亿美元。 VMware主…

20240326-1-KNN面试题

KNN面试题 1.简述一下KNN算法的原理 KNN算法利用训练数据集对特征向量空间进行划分。KNN算法的核心思想是在一个含未知样本的空间&#xff0c;可以根据样本最近的k个样本的数据类型来确定未知样本的数据类型。 该算法涉及的3个主要因素是&#xff1a;k值选择&#xff0c;距离度…

AOF文件重写

1.2.3.AOF文件重写 因为是记录命令&#xff0c;AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作&#xff0c;但只有最后一次写操作才有意义。通过执行bgrewriteaof命令&#xff0c;可以让AOF文件执行重写功能&#xff0c;用最少的命令达到相同效果。 如图&am…

SolidWorks上手直接开整

本科学3D建模的时候&#xff0c;学习过犀牛Rhine&#xff0c;当时就惊叹于入籍紧密集成的可视化编程环境&#xff0c;后来又简单学习过了3DMax、Maya&#xff0c;平时使用的频率不多&#xff0c;所以还是初学者水平&#xff0c;现在课题组需要自研一个原型机&#xff0c;需要工…

图片管理系统:原理、设计与实践

title: 图片管理系统&#xff1a;原理、设计与实践 date: 2024/4/9 20:04:25 updated: 2024/4/9 20:04:25 tags: 图片管理存储组织上传采集处理编辑搜索检索展示分享AI应用 第一章&#xff1a;图片管理系统概述 1.1 图片管理系统简介 图片管理系统是一种用于存储、组织、处理…