鸿蒙应用开发之全局状态管理:AppStorageV2轻松实现登录到个人中心数据共享

文章目录

    • 一、简介
    • 二、核心概念与用法详解
      • [2.1 核心 API 详解](#2.1 核心 API 详解)
    • [三、实战示例:登录 → 个人中心](#三、实战示例:登录 → 个人中心)
      • [3.1 定义共享数据模型](#3.1 定义共享数据模型)
      • [3.2 登录页面(LoginPage)](#3.2 登录页面(LoginPage))
      • [3.3 个人中心页面(ProfilePage)](#3.3 个人中心页面(ProfilePage))
      • [3.4 主页面与页面跳转](#3.4 主页面与页面跳转)
      • [3.5 运行效果验证](#3.5 运行效果验证)
    • 四、最佳实践与数据清理
    • 五、总结与对比

一、简介

AppStorageV2 是 HarmonyOS 提供的应用级全局状态管理方案。它通过键值对方式在应用的所有组件(跨 Ability、跨页面、跨组件层级)之间共享数据,且支持响应式更新------当共享数据发生变化时,所有绑定了该数据的 UI 会自动刷新。

AppStorageV2 并非 AppStorage 的简单升级,而是为状态管理 V2 架构设计的全新全局状态存储方案。

它是为了突破 V1 在响应式能力、数据流方向、与新型组件兼容性上的瓶颈而推出的。旧项目可继续使用 AppStorage,但新项目或需要向 V2 架构迁移的项目,官方建议优先使用 AppStorageV2,以获得更现代、更可靠的全局状态管理体验。

二、核心概念与用法详解

使用 AppStorageV2 主要分为三步:

  1. 定义数据类 :创建一个普通类,使用 @ObservedV2 装饰器标记它,并用 @Trace 装饰器标记你希望响应式更新的属性。
  2. 连接全局存储 :在任何一个组件中,使用 AppStorageV2.connect(ClassName, factory) 来获取或创建一个与该类绑定的全局单例。
  3. 读写与响应 :直接通过 connect 返回的实例读写被 @Trace 修饰的属性。所有 connect 了同一个类的组件都会自动收到变化通知并刷新 UI。

注意:如果你希望数据变化后 UI 自动刷新,并且希望获得属性级精准更新、避免无效渲染,那就必须用 @ObservedV2+ @Trace 修饰类及其属性。如果你只把 AppStorageV2 当作一个纯数据容器,且不需要 UI 自动响应内部属性的变化,完全可以去掉装饰器。

2.1 核心 API 详解

@ObservedV2 类装饰器

它告诉 AppStorageV2 系统,这个类是一个可被观察的数据模型。只有被它装饰的类,其实例才能被 AppStorageV2 管理。

@Trace 属性装饰器

标记在类属性上,表示"当这个属性的值发生变化时,需要通知所有观察者"。这是实现响应式的关键。没有被 @Trace 修饰的属性,即使所属类有 @ObservedV2,其变化也不会触发 UI 刷新。

AppStorageV2.connect<T>(type: new () => T, factory: () => T): T

此 API 用于连接到或创建一个指定类型的全局实例。

  • type : 你定义的、被 @ObservedV2 装饰的类的构造函数。
  • factory: 一个工厂函数。如果该类型的实例尚不存在于全局存储中,则会调用此函数创建一个新的;如果已存在,则直接返回已存在的实例。

注意:在整个应用进程中,同一个 Class 只会存在一个全局实例(单例模式)。

三、实战示例:登录 → 个人中心

下面通过一个完整的例子,演示如何在登录页写入用户信息,然后在个人中心页读取并展示。你将看到,两页之间无需通过路由传参,数据就能自动同步。

3.1 定义共享数据模型

首先,创建一个独立的文件 src/main/ets/model/UserData.ets 来存放我们的数据模型。

typescript 复制代码
@ObservedV2
export class UserData {
  @Trace username: string = '';
  @Trace isLoggedIn: boolean = false;
}

3.2 登录页面(LoginPage)

typescript 复制代码
// src/main/ets/pages/LoginPage.ets
import { AppStorageV2, router } from '@kit.ArkUI';
import { UserData } from '../model/UserData';

@Entry
@ComponentV2
export struct LoginPage {
  @Local userData: UserData = AppStorageV2.connect(UserData, () => new UserData())!;
  @Local inputValue: string = '';

  build() {
    Column({ space: 16 }) {
      Text('登录页')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      TextInput({ placeholder: '请输入用户名', text: this.inputValue })
        .onChange((value: string) => {
          this.inputValue = value;
        })
        .width('80%')

      Button('登录')
        .width('80%')
        .onClick(() => {
          if (this.inputValue.trim().length > 0) {
            this.userData.username = this.inputValue.trim();
            this.userData.isLoggedIn = true;
            router.push({
              url: 'pages/ProfilePage'
            })
          }
        })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

关键点@Local userData 通过 AppStorageV2.connect 初始化。当我们修改 this.userData.username 时,这个更改会立刻同步到全局存储中。

运行效果:

3.3 个人中心页面(ProfilePage)

typescript 复制代码
// src/main/ets/pages/ProfilePage.ets
import { AppStorageV2 } from '@kit.ArkUI';
import { UserData } from '../model/UserData';

@Entry
@ComponentV2
export struct ProfilePage {
  @Local userData: UserData = AppStorageV2.connect(UserData, () => new UserData())!;

  build() {
    Column({ space: 16 }) {
      Text('个人中心')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      if (this.userData.isLoggedIn) {
        Text(`欢迎您,${this.userData.username}`)
          .fontSize(20)
          .fontColor('#FF6600')
      } else {
        Text('未登录')
          .fontSize(18)
          .fontColor(Color.Gray)
      }
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

关键点ProfilePage 也通过同样的代码 AppStorageV2.connect(UserData, () => new UserData())! 获取实例。因为 UserData 类型的全局实例已经在 LoginPage 中创建,所以这里只会获取并复用同一个实例,从而读取到最新的用户数据。

运行效果:

3.4 主页面与页面跳转

typescript 复制代码
// src/main/ets/pages/Index.ets
import { router } from '@kit.ArkUI';
import { AppStorageV2 } from '@kit.ArkUI';
import { UserData } from '../model/UserData';

@Entry
@ComponentV2
struct Index {
  @Local userData: UserData = AppStorageV2.connect(UserData, () => new UserData())!;

  build() {
    Column({ space: 20 }) {
      Button('去登录')
        .width('80%')
        .onClick(() => {
          router.pushUrl({
            url: 'pages/LoginPage'
          });
        })
      Button('去个人中心')
        .width('80%')
        .onClick(() => {
          router.pushUrl({
            url: 'pages/ProfilePage'
          });
        })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

3.5 运行效果验证

  1. 启动应用,点击"去登录"。
  2. 在登录页输入用户名,点击"登录"。
  3. 返回主页,点击"去个人中心",你会看到用户名已经自动显示为刚才输入的值。
  4. 再次回到登录页,修改用户名并再次登录,然后重新进入个人中心,你会发现用户名也同步更新了。整个过程无需任何组件间手动传参。

运行效果:

四、最佳实践与数据清理

AppStorageV2 的全局实例与应用进程共存。如果你在登录时存储了用户信息,但在用户退出登录时不清除,那么下次打开应用时,应用可能还会显示上次登录的用户名,这不是我们想要的行为。

因此,强烈建议 在用户退出登录时,使用 AppStorageV2.remove() 方法手动清理数据。

typescript 复制代码
// 在退出登录的方法中调用
import { AppStorageV2 } from '@kit.arkui';
import { UserData } from '../model/UserData';

function logout() {
  // ... 执行其他退出逻辑

  // 移除全局存储中的 UserData 实例
  AppStorageV2.remove(UserData);
}

调用 remove 后,所有 connectUserData 的组件都会被通知,并尝试重新通过 factory 函数创建新的实例,从而恢复到初始状态。

运行效果:

五、总结与对比

要点 说明
需要响应式的属性用 @Trace 只标记你需要响应 UI 变化的属性,避免不必要的性能开销。
connect 返回的是同一个实例 理解这个"单例"特性是正确使用的关键。
退出登录时建议 remove 这是数据清理的好习惯,避免旧数据污染新会话。
生命周期为应用进程级 @State@Prop 等组件级状态管理不同,它是全局的。

AppStorageV2 非常适合管理全局用户登录状态、应用主题配置、多语言等需要在不同页面间共享的数据。相比于 AppStorageV1(使用键值字符串存取),V2 版本提供了更现代、类型安全、面向对象的使用方式,是 HarmonyOS 全局状态管理的首选方案。

相关推荐
进击的前栈1 小时前
鸿蒙实战:全栈回顾——Kit API 全景、架构总结与未来演进
华为·架构·harmonyos
在书中成长2 小时前
HarmonyOS 小游戏《对战五子棋》开发第33篇 - AI异步落子与setTimeout
人工智能·harmonyos
listening7772 小时前
HarmonyOS 6.1 分布式文件服务实战:跨设备商品图片/视频秒开方案
wpf·harmonyos
xianjixiance_2 小时前
鸿蒙实战:BindRelationPage 四步状态机与邀请卡倒计时
华为·harmonyos·鸿蒙系统
解局易否结局2 小时前
鸿蒙三方库生态与实战:从安装到发布全链路指南
深度学习·华为·harmonyos
在书中成长2 小时前
HarmonyOS 小游戏《对战五子棋》开发第31篇 - TwoPlayerPage双人对战(三):结果弹窗与游戏结束处理
harmonyos
绝世番茄2 小时前
鸿蒙HarmonyOS ArkTS原生学习:缩放手势实现 PinchToZoom 深度解析
学习·华为·harmonyos·鸿蒙
进击的前栈2 小时前
鸿蒙实战:19 页面全景汇总与 7 大共享设计模式回顾
华为·设计模式·harmonyos
ujainu小2 小时前
原生性能优化:6变量实现高效桥接
开发语言·华为·性能优化·harmonyos