前面学的 @State / @Link / @ObjectLink 都是组件 / 父子之间的状态。一旦需要跨页面共享数据(比如登录 token、用户信息、全局主题),单纯靠路由传参非常麻烦。ArkTS 提供 AppStorage,专门用来存放应用全局状态,整个 App 所有页面都可以读取、监听。

一句话理解:AppStorage 是全局的状态仓库,数据存在应用内存;搭配 PersistentStorage 可以把数据持久化到本地,App 重启后数据还在(适合记住登录状态)。

一、AppStorage 基础概念

  • AppStorage:全局内存存储,应用运行期间有效,App 关闭就清空。
  • 可以在任意页面读写、监听变化;
  • 推荐用 @StorageProp / @StorageLink 装饰器绑定,自动响应数据变化;
    • @StorageProp:单向绑定,读取全局数据,本地修改不回写全局(本地副本)
    • @StorageLink:双向绑定,修改变量,全局仓库同步更新

误区:不要把所有数据都塞进 AppStorage。只放全局共享数据:token、用户信息、主题、全局配置;页面局部状态继续用 @State,全局仓库放太多数据会增加性能开销。

1. 基础用法:@StorageLink 双向绑定全局变量

​
import AppStorage from '@ohos.app.ability.AppStorage';

// 初始化全局变量(建议放在入口页面/ability中一次性初始化)
AppStorage.setOrCreate('userName', '游客');

@Entry
@Component
struct PageA {
  // 双向绑定全局key:userName
  @StorageLink('userName') globalName: string;

  build() {
    Column() {
      Text(`全局用户名:${this.globalName}`).fontSize(22)
      Button("修改全局名字")
        .onClick(() => {
          this.globalName = "小明";
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

​

新建 PageB.ets,在另一个页面读取同一份全局数据:

​
@Entry
@Component
struct PageB {
  @StorageLink('userName') globalName: string;

  build() {
    Column() {
      Text(`PageB读取全局名字:${this.globalName}`).fontSize(22)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

​

关键点:

  1. AppStorage.setOrCreate(key, 默认值):如果 key 不存在就创建,存在就不覆盖;
  2. @StorageLink('key'):双向绑定,当前组件修改,所有绑定这个 key 的页面全部自动刷新 UI;
  3. key 是字符串,全局唯一。

2. @StorageProp 单向全局读取(副本)

​
@Entry
@Component
struct StoragePropDemo {
  // 单向:从全局读取,本地修改只是副本,不会改动AppStorage
  @StorageProp('userName') localName: string;

  build() {
    Column() {
      Text(`单向读取全局:${this.localName}`)
      Button("修改本地副本(不会改全局)")
        .onClick(() => {
          this.localName = "临时名字";
        })
    }
  }
}

​
  • @StorageProp:拿到的是副本;本地修改不会同步到全局;
  • 但如果源头 AppStorage 的值被别的页面修改,当前页面会自动同步最新值。

3. 复杂对象存入 AppStorage(用户信息实体)

⚠️重点:对象存入 AppStorage,class 必须加 @ObservedObject,否则修改对象内部属性 UI 不刷新。

​
import AppStorage from '@ohos.app.ability.AppStorage';

@ObservedObject
class User {
  id: number;
  name: string;
  token: string;
  constructor(id: number, name: string, token: string) {
    this.id = id;
    this.name = name;
    this.token = token;
  }
}

// 初始化全局用户对象
AppStorage.setOrCreate('loginUser', new User(0, "游客", ""));

@Entry
@Component
struct GlobalUserDemo {
  @StorageLink('loginUser') user: User;

  build() {
    Column() {
      Text(`用户:${this.user.name},token:${this.user.token}`).fontSize(18)
      Button("登录,更新全局用户信息")
        .onClick(() => {
          this.user.id = 1001;
          this.user.name = "张三";
          this.user.token = "abc123456";
        })
      Button("退出登录")
        .onClick(() => {
          this.user = new User(0, "游客", "");
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

​

4. PersistentStorage 持久化:App 重启依然保留登录态

AppStorage 只是内存存储,App 杀掉之后数据丢失。 PersistentStorage 可以把指定 key 持久化到本地数据库,App 重启、手机重启,数据还在,适合保存记住登录、主题设置。

​
import PersistentStorage from '@ohos.app.ability.PersistentStorage';
import AppStorage from '@ohos.app.ability.AppStorage';

// 在EntryAbility.ts的onCreate里面初始化持久化
// 把AppStorage里面的loginToken开启持久化
PersistentStorage.persistProp('loginToken', '');

// 页面中使用
@Entry
@Component
struct PersistDemo {
  @StorageLink('loginToken') token: string;

  build() {
    Column() {
      Text(`本地保存的token:${this.token}`)
      Button("保存token")
        .onClick(() => {
          this.token = "test_token_666";
        })
      Button("清空token")
        .onClick(() => {
          this.token = "";
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

​

关键点:

  1. persistProp (key, 默认值),推荐放在 EntryAbility.ts onCreate,App 启动时加载;
  2. 持久化只支持基础类型:string、number、boolean;复杂 class 对象不能直接持久化,对象持久化需要手动转 JSON 字符串存储。

5. 原生 API:直接读写 AppStorage(不绑定装饰器)

有时候不在 UI 组件里(比如 http 请求工具类),不能使用 @StorageLink,直接调用 API 读写:

​
import AppStorage from '@ohos.app.ability.AppStorage';

// 设置
AppStorage.set('userName', "李四");
// 获取
const name = AppStorage.get<string>('userName');
// 删除key
AppStorage.delete('userName');

​

六、AppStorage 高频踩坑汇总

坑 1:复杂对象不加 @ObservedObject,修改内部属性页面不刷新

class 实体必须加 @ObservedObject,否则对象内部字段变更不会触发 UI 更新。

坑 2:PersistentStorage 直接持久化 class 对象

❌错误:persistProp 存 User 对象。持久化仅支持基础类型,对象需要 JSON.stringify 转字符串存入,读取再 JSON.parse 还原。

坑 3:全局 key 命名冲突

多个地方定义同名 key,数据互相覆盖。建议统一维护全局 key 常量。

坑 4:滥用 AppStorage,大量页面状态放全局

局部页面状态不要进全局仓库,会造成状态难以追踪、调试困难。

坑 5:忘记初始化 setOrCreate,@StorageLink 绑定 undefined

页面直接 @StorageLink 绑定 key,没有提前初始化,容易出现 undefined 报错。推荐在 EntryAbility 初始化全局默认值。

七、全局状态选型速查表

API / 装饰器作用数据位置生命周期
AppStorage全局状态仓库内存App 运行期间,关闭 App 清空
@StorageLink('key')双向绑定全局 key内存修改同步全局,UI 自动刷新
@StorageProp('key')单向读取全局,本地副本内存源头变更同步,本地修改不回写
PersistentStorage持久化存储本地文件数据库App 重启、手机重启数据保留(仅基础类型)

结尾总结

  1. AppStorage 是应用全局内存状态,跨页面共享登录信息、全局配置;
  2. @StorageLink 双向绑定,@StorageProp 单向副本;
  3. 复杂 class 实体存入 AppStorage,类必须加 @ObservedObject;
  4. PersistentStorage 持久化仅支持基础类型,用来保存 token、主题开关;对象持久化要手动 JSON 序列化;
  5. 尽量精简全局仓库,局部状态继续使用 @State。

实操指南

  1. 在 EntryAbility 初始化全局登录用户(@ObservedObject User 类);
  2. 登录页点击登录,更新 AppStorage 用户信息;
  3. 首页读取全局用户信息展示;
  4. token 用 PersistentStorage 持久化保存,重启 App 仍然保留登录凭证。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐