【鸿蒙 HarmonyOS 4.0】应用状态:LocalStorage/AppStorage/PersistentStorage

news2024/12/23 21:03:02

一、介绍

如果要实现应用级的,或者多个页面的状态数据共享,就需要用到应用级别的状态管理的概念。

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

二、LocalStorage:页面级UI状态存储

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

LocalStorage根据与@Component装饰的组件的同步类型不同,提供了两个装饰器:

✍@LocalStorageProp装饰的变量和与LocalStorage中给定属性建立单向同步关系。

✍@LocalStorageLink装饰的变量和在@Component中创建与LocalStorage中给定属性建立双向同步关系。

2.1、从应用逻辑使用LocalStorage

let storage = new LocalStorage({ 'PropA': 47 }); // 创建新实例并使用给定对象初始化

let propA = storage.get('PropA') // propA == 47
let link1 = storage.link('PropA'); // link1.get() == 47
let link2 = storage.link('PropA'); // link2.get() == 47
let prop = storage.prop('PropA'); // prop.get() = 47

link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
prop.set(1); // one-way sync: prop.get()=1; but link1.get() == link2.get() == 48
link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49

2.2、从UI内部使用LocalStorage

2.2.1、使用步骤:

①使用构造函数创建LocalStorage实例storage;

②使用@Entry装饰器将storage添加到LocalStoragePage顶层组件中;

③建立数据同步

@LocalStorageLink绑定LocalStorage对给定的属性,建立双向数据同步。

@LocalStorageProp绑定LocalStorage对给定的属性,建立单向数据同步

2.2.2、@LocalStorageProp和LocalStorage建立单向同步的场景

// 创建新实例并使用给定对象初始化
let storage = new LocalStorage({ name:'Tom' });
// 使LocalStorage可从@Component组件访问
@Entry(storage)
@Component
struct LocalStoragePage {
  // @LocalStorageProp变量装饰器与LocalStorage中的'name'属性建立单向绑定
  @LocalStorageProp('name') myName:string = ''

  build() {
    Row() {
      Column() {
        Text(this.myName)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
        //点击按钮后,只改变当前组件显示的myName,不会同步到LocalStorage中
        Button('更改名字').onClick(()=>{
          this.myName = 'jack'
        })
        //子组件Child
        Child()
      }
      .width('100%')
    }
    .height('100%')
  }
}

@Component
struct Child {
  // @LocalStorageProp变量装饰器与LocalStorage中的'name'属性建立单向绑定
  @LocalStorageProp('name') myName:string = ''
  build() {
    Row(){
      //当父组件改变时,子组件不会改变,myName显示 'Tom'
      Text(`Child-${this.myName}`).fontSize(30)
    }
  }
}

说明:

在上面的示例中, LocalStoragePage组件和Child组件分别在本地创建了与storage的'name'对应属性的单向同步的数据,可以看到:

  • LocalStoragePage中对this.myName的修改,只会在LocalStoragePage中生效,并没有同步回storage;
  • Child组件中,Text绑定的myName 依旧显示 'Tom'。

2.2.3、@LocalStorageLink和LocalStorage双向同步的场景

// 创建新实例并使用给定对象初始化
let storage = new LocalStorage({ name:'Tom' });
// 使LocalStorage可从@Component组件访问
@Entry(storage)
@Component
struct LocalStoragePage {
  // @LocalStorageLink变量装饰器与LocalStorage中的'name'属性建立双向绑定
  @LocalStorageLink('name') myName:string = ''

  build() {
    Row() {
      Column() {
        Text(this.myName)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
        //点击按钮后,当前组件显示的myName,会同步到LocalStorage中
        Button('更改名字').onClick(()=>{
          this.myName = 'jack'
        })
        //子组件Child
        Child()
      }
      .width('100%')
    }
    .height('100%')
  }
}

@Component
struct Child {
  // @LocalStorageLink变量装饰器与LocalStorage中的'name'属性建立双向绑定
  @LocalStorageLink('name') myName:string = ''
  build() {
    Row(){
      //当父组件改变时,子组件也会改变,myName显示 'jack'
      Text(`Child-${this.myName}`).fontSize(30)
    }
  }
}

说明:

在上面的示例中, LocalStoragePage组件和Child组件分别在本地创建了与storage的'name'对应属性的双向同步的数据,可以看到:

  • LocalStoragePage中对this.myName的修改,会同步到storage中
  • 父组件发生变化后,Child组件中,Text绑定的myName 也会改变为 'jack'。

拓展:

数据双向同步时,在父组件点击按钮通过this.myName进行名字的修改,还有一种写法是直接通过storage的set方法来改变name的值,如下写法:

点击按钮后,storage中的name值由'Tom'更改为'rose',父子组件中都发生了改变

        //点击按钮后,当前组件显示的myName,会同步到LocalStorage中
        Button('更改名字')
          .onClick(()=>{
          // this.myName = 'jack'
          storage.set('name','rose')
        })

2.3、将LocalStorage实例从UIAbility共享到一个或多个视图

2.3.1、使用步骤

①​ 在所属UIAbility中创建LocalStorage实例,并调用windowStage.loadContent。

②创建2个UI页面,在UI页面通过GetShared接口获取在通过loadContent共享的LocalStorage实例

备注:LocalStorage.GetShared只在模拟器或者实机上才有效,不能在Preview预览器中使用。

// Comp1.ets

import router from '@ohos.router'
// 通过getShared接口获取stage共享的LocalStorage实例
let storage = LocalStorage.GetShared()
@Entry(storage)
@Component
struct Comp1 {
  @LocalStorageLink('cityName') cityName:string = ''

  build() {
    Row() {
      Column() {
        Text('Comp1'+'-'+this.cityName)
          .fontSize(30)
          .fontWeight(FontWeight.Bold)
        Button('去Comp1')
          .onClick(()=>{
            router.pushUrl({
              url:'pages/Comp2'
            })
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}
// Comp2.ets

import router from '@ohos.router'
// 通过getShared接口获取stage共享的LocalStorage实例
let storage = LocalStorage.GetShared()
@Entry(storage)
@Component
struct Comp2 {
  @State message:string = 'Comp2'
  @LocalStorageLink('cityName') cityName:string = ''

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(30)
          .fontWeight(FontWeight.Bold)
        Button('返回Comp1')
          .onClick(()=>{
            this.cityName = '深圳'
            router.back()
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

说明:

以上分别为Comp1页面与Comp2页面

Comp1页面通过getShared接口获取stage共享的LocalStorage实例,使用Text展示cityName初始值为'北京',并跳转至Comp2页面

Comp2页面也通过getShared接口获取stage共享的LocalStorage实例,在返回Comp1页面前,先将cityName值更改为'深圳',所以返回到Comp1页面时,呈现的cityName值已更改为'深圳'了

三、AppStorage:应用全局的UI状态存储 

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

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

✍@StorageProp(key)是和AppStorage中key对应的属性建立单向数据同步

✍@StorageLink(key)是和AppStorage中key对应的属性建立双向数据同步

3.1、从应用逻辑使用AppStorage

AppStorage.SetOrCreate('PropA', 47);

let propA: number = AppStorage.Get('PropA') // propA in AppStorage == 47, propA in LocalStorage == 17
var link1: SubscribedAbstractProperty<number> = AppStorage.Link('PropA'); // link1.get() == 47
var link2: SubscribedAbstractProperty<number> = AppStorage.Link('PropA'); // link2.get() == 47
var prop: SubscribedAbstractProperty<number> = AppStorage.Prop('PropA'); // prop.get() == 47

link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48
link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49

AppStorage.Get('PropA') // == 49
link1.get() // == 49
link2.get() // == 49
prop.get() // == 49

3.2、从UI内部使用AppStorage

@StorageLink变量装饰器与AppStorage配合使用,此装饰器使用AppStorage中的属性创建双向数据同步。


AppStorage.SetOrCreate('money', 50);

@Entry
@Component
struct AppStoragePage {
  @StorageLink('money') storLink: number = 1;

  build() {
    Row() {
      Column() {
        Text(`AppStorage ${this.storLink}`)
          .fontSize(30)
          .onClick(() => this.storLink += 1)
      }
      .width('100%')
    }
    .height('100%')
  }
}

四、PersistentStorage:持久化存储UI状态

LocalStorage和AppStorage都是运行时的内存,但是在应用退出再次启动后,依然能保存选定的结果,那便需要用到PersistentStorage

PersistentStorage是应用程序中的可选单例对象。此对象的作用是持久化存储选定的AppStorage属性,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同。

PersistentStorage允许的类型和值有:

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

注意:

①PersistentStorage的持久化变量最好是小于2kb的数据,不要大量的数据持久化,因为PersistentStorage写入磁盘的操作是同步的,大量的数据本地化读写会同步在UI线程中执行,影响UI渲染性能。如果开发者需要存储大量的数据,建议使用数据库api。

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

示例:

PersistentStorage.PersistProp('highScore', '0');

4.1、使用场景

从AppStorage中访问PersistentStorage初始化的属性

1、初始化PersistentStorage:

PersistentStorage.PersistProp('money', 50);

 2、在AppStorage获取对应属性:

AppStorage.Get('money'); // returns 50

 或在组件内部定义:

@StorageLink('money') money:number = 10;

完整代码如下:

PersistentStorage.PersistProp('money',50)

@Entry
@Component
struct PersistentStoragePage {
  @State message: string = 'Hello PersistentStoragePage'
  @StorageLink('money') money:number = 10
  build() {
    Row() {
      Column({space:10}) {
        Text(this.message).fontSize(30)
        // 应用退出时会保存当前结果。重新启动后,会显示上一次的保存结果
        Text(`money:${this.money}`).fontSize(30).fontWeight(FontWeight.Bold)
          .onClick(()=>{
            this.money += 1
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

说明:

点击money所增加的数字,应用退出时会保存当前结果。重新启动页面,会显示上一次的保存结果

当前持久化存储在API9模拟器上暂不支持。

4.2、PersistentStorage与AppStorage访问顺序

正确顺序为:AppStorage需在 PersistentStorage之后访问

需要先判断是否需要覆盖上一次保存在PersistentStorage中的值,如果需要覆盖,再调用AppStorage的接口进行修改,如果不需要覆盖,则不调用AppStorage的接口。

PersistentStorage.PersistProp('aProp', 48);
if (AppStorage.Get('aProp') > 50) {
    // 如果PersistentStorage存储的值超过50,设置为47
    AppStorage.SetOrCreate('aProp',47);
}

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

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

相关文章

ElasticSearch之数据分片和故障转移

写在前面 基础环境可以参考ElasticSearch之分布式模型介绍&#xff0c;选主&#xff0c;脑裂 。 本文看下es的数据分片和故障转移相关内容。 1&#xff1a;数据分片 分片&#xff0c;英文是shard&#xff0c;存储在data node &#xff0c;分为主分片和副本分片&#xff0c;英…

数据治理实战——翼支付金融板块业务数仓建设和数据治理之路

目录 一、数据治理背景 二、数据治理建设内容 2.1 组织协同 2.2 平台建设 2.3 数据应用治理 2.4 数据规范 2.5 数据安全 三、企业级数仓建设 3.1 调研阶段 2.2 平台护航 2.3 数仓分层 2.4 维度建模 2.4.1 维度建模四步曲 2.4.2 命名规范 2.4.3 资产沉淀 2.4.4 …

【JS】WebSocket:实现实时通信功能。

【JS】WebSocket:实现实时通信功能。 一、WebSocket是什么&#xff1f;二、为什么需要WebSocket?三、WebSocket的优势四、WebSocket实现方式五、示例1&#xff1a;实时数据展示六、示例2&#xff1a;实现简易聊天室 如果想需要websocket实现功能&#xff0c;后端也要进行对应的…

前端食堂技术周刊第 114 期:Interop 2024、TS 5.4 RC、2 月登陆浏览器的新功能、JSR、AI SDK 3.0

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;凉拌鸡架 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 大家好&#xff0c;我是童欧巴。欢迎来到前端食堂技术周刊&#xff0c;我们先来看下…

tsc : 无法加载文件 C:\Users\Administrat\AppData\Roaming\npm\tsc.ps 1,因为在此系统上禁止运行脚本

报错&#xff1a;tsc : 无法加载文件 C:\Users\Administrat\AppData\Roaming\npm\tsc.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 解决 使用命令行时出现ab…

Excel中筛选合并单元格后,只显示第一行怎么办?

Excel中筛选合并单元格后,只显示第一行怎么办? 我们日常的Excel数据在展示的时候为了数据的清晰和美观往往部分相同的单元格进行合并,但是合并之后在筛选时会发现结果会显示异常。 现在我们筛选下国籍为中国的员工信息,发现只显示了一条数据,解决这个异常只需要五Excel步:…

使用Pytorch导出自定义ONNX算子

在实际部署模型时有时可能会遇到想用的算子无法导出onnx&#xff0c;但实际部署的框架是支持该算子的。此时可以通过自定义onnx算子的方式导出onnx模型&#xff08;注&#xff1a;自定义onnx算子导出onnx模型后是无法使用onnxruntime推理的&#xff09;。下面给出个具体应用中的…

【Maven】Maven 基础教程(四):搭建 Maven 私服 Nexus

《Maven 基础教程》系列&#xff0c;包含以下 4 篇文章&#xff1a; Maven 基础教程&#xff08;一&#xff09;&#xff1a;基础介绍、开发环境配置Maven 基础教程&#xff08;二&#xff09;&#xff1a;Maven 的使用Maven 基础教程&#xff08;三&#xff09;&#xff1a;b…

JVM(类加载机制)

类加载就是 .class 文件, 从文件(硬盘) 被加载到内存(元数据区)中的过程 类加载的过程 加载: 找 .class 文件的过程, 打开文件, 读文件, 把文件读到内存中 验证: 检查 .class 文件的格式是否正确 .class 是一个二进制文件, 其格式有严格的说明 准备: 给类对象分配内存空间 (先在…

c++ thread的使用 调用类里面的函数和调用类外的函数的区别

1.thread 调用类外的函数。 在使用thread之前要加上#include <thread>。 例1&#xff1a; #include <iostream> #include <thread> using namespace std; void Threadfunc1() {cout << "Threadfunc1" << endl; }void Threadfunc2(in…

sqllab 11-22

11.有回显&#xff0c;单引号 首先判断是字符型还是数字型 通过order by 来获取字段数 方便后续union联合 注意这里mime表明了内容要进行url编码&#xff0c;测试3报错&#xff0c;2正常&#xff0c;所以有2列。 还需要判断显示位&#xff0c;因为只有显示位的数据才能被爆出…

基于springboot+vue的多媒体素材库的开发与应用系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Python处理表格数据库之Agate使用详解

概要 您是否有时觉得在处理表格数据时感到不知所措? 也许你在处理一个大型 CSV 文件,遇到了各种数据不一致的问题,或者需要验证数据,确保其准确无误才能进行下一步分析。 传统的数据分析库或许功能强大,但学习曲线陡峭,用起来有点杀鸡用牛刀的感觉。 这时,有一个更…

Redis是AP的还是CP的?

redis是一个开源的内存数据库&#xff0c;那么他到底是AP的还是CP的呢&#xff1f; 有人说&#xff1a;单机的是redis是cp的&#xff0c;而集群的redis是ap的&#xff1f; 但是我不这么认为&#xff0c;我觉得redis就是ap的&#xff0c;虽然在单机redis中&#xff0c;因为只有…

计算机网络实验 基于ENSP的协议分析

实验二 基于eNSP的协议分析 一、实验目的&#xff1a; 1&#xff09;熟悉VRP的基本操作命令 2&#xff09;掌握ARP协议的基本工作原理 3&#xff09;掌握IP协议的基本工作原理 4&#xff09;掌握ICMP协议的基本工作原理 二、实验内容&#xff1a; 1、场景1&#xff1a;两台PC机…

力扣每日一题 用队列实现栈 模拟

Problem: 225. 用队列实现栈 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 力扣官解 辅助队列存栈顶元素主队列存逆序序列 复杂度 时间复杂度: 添加时间复杂度, 示例&#xff1a; O ( n ) O(n) O(n) 空间复杂度: 添加空间复杂度, 示例&#xff1a; O ( …

Markdown的语法使用

目录 前言一、Markdown基本使用二、基本使用补充2.1 三、特殊字符四、数学公式 前言 Markdown是网页版的文本编辑器&#xff0c;Markdown 允许您使用易于阅读、易于编写的纯文本格式进行编写&#xff0c;然后将其转换为结构有效的 XHTML&#xff08;或 HTML&#xff09;。本文主…

【C语言】内存操作篇---动态内存管理----malloc,realloc,calloc和free的用法【图文详解】

欢迎来CILMY23的博客喔&#xff0c;本篇为【C语言】内存操作篇---动态内存管理----malloc&#xff0c;realloc&#xff0c;calloc和free的用法【图文详解】&#xff0c;感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 前言 在学完结构体后&#xff08;…

《Trustzone/TEE/安全-实践版》介绍

第一章&#xff1a;课程说明和准备 课程介绍和说明 资料准备 为什么使用qemu_v8环境&#xff1f; 为什么选择香橙派开发板&#xff1f; optee qemu_v8环境展示 香橙派optee环境展示 第二章&#xff1a;Qemu环境搭建 ubuntu20.04的安装(virtualboxubuntu20.04) 搭建optee qem…

云手机的境外舆情监控应用——助力品牌公关

在当今数字化时代&#xff0c;社交媒体已成为品牌传播和互动的主要平台。随之而来的是海量的信息涌入&#xff0c;品牌需要及时了解并应对海外社交媒体上的舆情变化。本文将介绍如何通过云手机进行境外舆情监控&#xff0c;更好地帮助企业公关及时作出决策。 1. 境外舆情监控与…