OpenHarmony AppStorage 全局状态管理实战:全局数据共享 + Preferences 持久化联动
前面学习了页面路由、本地 Preferences 存储、网络请求,多页面开发时常遇到:首页、个人中心、设置页共用用户信息、登录状态,跨页面传参繁琐。AppStorage 是 ArkUI 内置全局状态容器,用来存储应用全局共享数据,一处修改、全页面自动刷新 UI;结合 Preferences 可实现「打开 App 从本地加载→运行时全局读写→退出自动持久化保存」完整方案,是项目全局数据最优方案。适用
·
一、前言
前面学习了页面路由、本地 Preferences 存储、网络请求,多页面开发时常遇到:首页、个人中心、设置页共用用户信息、登录状态,跨页面传参繁琐。AppStorage 是 ArkUI 内置全局状态容器,用来存储应用全局共享数据,一处修改、全页面自动刷新 UI;结合 Preferences 可实现「打开 App 从本地加载→运行时全局读写→退出自动持久化保存」完整方案,是项目全局数据最优方案。
适用场景:登录状态、用户昵称、系统主题色、全局配置、用户头像。
二、基础概念
- AppStorage:应用级全局单例仓库,全局唯一,所有页面均可存取;
AppStorage.SetOrCreate(key,defaultVal):没有则创建、已有则取值(最常用);@StorageLink("key"):组件绑定全局变量,双向绑定,修改变量自动同步全局、全局改动页面自动刷新;@StorageProp("key"):单向绑定,只能读取全局数据,无法在当前组件修改;- 配合 Preferences:应用启动读取本地数据存入 AppStorage,数据变更同步写入本地,实现永久保存。
三、基础 API 使用示例
3.1 全局注册变量(通常放在入口页面 aboutToAppear)
ets
@Entry
@Component
struct Index {
aboutToAppear() {
// 注册全局登录状态、用户名,默认未登录
AppStorage.SetOrCreate<boolean>("isLogin", false)
AppStorage.SetOrCreate<string>("userName", "游客")
}
build() {
Column({ space:20 }) {
Text("首页页面")
NavRouter()
}
.width("100%")
.height("100%")
.padding(30)
}
}
// 子组件:双向绑定全局数据
@Component
struct NavRouter {
// 双向绑定全局key
@StorageLink("isLogin") login:boolean
@StorageLink("userName") name:string
build() {
Column({space:10}) {
Text(this.login ? `欢迎:${this.name}` : "当前游客模式")
.fontSize(18)
Button("模拟登录修改全局数据")
.onClick(()=>{
// 修改变量=修改全局AppStorage,所有绑定页面同步刷新
this.login = true
this.name = "鸿蒙开发工程师"
})
}
}
}
3.2 新页面读取全局数据(路由跳转页面)
ets
import router from '@ohos.router'
@Entry
@Component
struct MinePage {
// 单向绑定,仅读取,不能修改
@StorageProp("isLogin") isLogin:boolean
@StorageProp("userName") uname:string
build() {
Column({space:20}) {
Text("个人中心页面").fontSize(22)
Text(`登录状态:${this.isLogin?"已登录":"未登录"}`)
Text(`用户名称:${this.uname}`)
Button("返回首页").onClick(()=>router.back())
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
关键特性:首页点击登录修改全局,个人中心页面无需传参、自动同步最新数据。
四、AppStorage 常用原生方法
ets
// 获取全局值
let login = AppStorage.Get<boolean>("isLogin")
// 修改全局值
AppStorage.Set<string>("userName","新名字")
// 删除全局key
AppStorage.Delete("userName")
// 清空全部
AppStorage.Clear()
五、进阶:AppStorage + Preferences 持久化联动(项目核心方案)
业务逻辑:
- APP 启动 → Preferences 读取本地保存的用户信息 → 存入 AppStorage;
- 页面修改全局用户数据 → AppStorage 变更 → 自动写入 Preferences;
- 重启 APP,数据不会丢失。
ets
import preferences from '@ohos.data.preferences'
import common from '@ohos.app.ability.common'
// 全局持久化工具类
class GlobalStoreUtil {
static context:common.UIAbilityContext
static FILE_NAME:string = "global_user"
// 初始化:从本地读取数据存入AppStorage,程序启动调用
static async initFromLocal() {
let pre = await preferences.getPreferences(this.context,this.FILE_NAME)
// 读取本地值,无数据用默认值
let localLogin = await pre.get("isLogin",false)
let localName = await pre.get("userName","游客")
// 存入全局仓库
AppStorage.SetOrCreate("isLogin",localLogin)
AppStorage.SetOrCreate("userName",localName)
}
// 全局数据变化,保存到本地
static async saveToLocal() {
let pre = await preferences.getPreferences(this.context,this.FILE_NAME)
pre.putSync("isLogin",AppStorage.Get("isLogin"))
pre.putSync("userName",AppStorage.Get("userName"))
await pre.flush()
}
}
@Entry
@Component
struct AppEntry {
aboutToAppear() {
// 初始化上下文
GlobalStoreUtil.context = getContext(this) as common.UIAbilityContext
// 从本地加载数据进全局
GlobalStoreUtil.initFromLocal()
}
// 绑定全局
@StorageLink("isLogin") login:boolean
@StorageLink("userName") name:string
build() {
Column({space:25}) {
Text("全局状态+持久化演示").fontSize(22).fontWeight(FontWeight.Bold)
Text(`用户:${this.name} | ${this.login?"已登录":"未登录"}`).fontSize(18)
Button("登录(修改全局并保存本地)")
.width(220)
.onClick(async()=>{
this.login = true
this.name = "OpenHarmony开发者"
// 变更持久化
await GlobalStoreUtil.saveToLocal()
})
Button("退出登录(清空全局并保存)")
.width(220)
.onClick(async()=>{
this.login = false
this.name = "游客"
await GlobalStoreUtil.saveToLocal()
})
Button("跳转个人中心页")
.width(220)
.onClick(()=>{
import router from '@ohos.router'
router.pushUrl({url:"pages/mine/mine"})
})
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
mine 页面(pages/mine/mine.ets)
ets
@Entry
@Component
struct Mine {
@StorageProp("isLogin") login:boolean
@StorageProp("userName") name:string
build() {
Column({space:15}) {
Text("个人中心").fontSize(22)
Text(`登录状态:${this.login}`)
Text(`用户名:${this.name}`)
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
效果:登录后关闭应用,再次打开 APP 依旧保留登录状态和用户名。
六、综合实战:登录页网络请求→保存全局 + 本地
结合之前 Fetch 登录接口、Preferences、AppStorage 三合一完整业务:
ets
import preferences from '@ohos.data.preferences'
// 沿用前面封装HttpUtil
class HttpUtil{
static async post(url:string,data:Object){
let opt:RequestInit={
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify(data)
}
let res=await fetch(url,opt)
return res.json()
}
}
@Entry
@Component
struct LoginPage {
@State account:string=""
@State pwd:string=""
@StorageLink("isLogin") loginFlag:boolean
@StorageLink("userName") nick:string
// 登录接口请求
async submitLogin() {
try{
let res = await HttpUtil.post("https://jsonplaceholder.typicode.com/users",{
name:this.account,pwd:this.pwd
})
// 登录成功,修改全局
this.loginFlag=true
this.nick=this.account
// 持久化本地
await GlobalStoreUtil.saveToLocal()
AlertDialog.show({title:"提示",message:"登录成功"})
import router from '@ohos.router'
router.back()
}catch(e){
AlertDialog.show({title:"提示",message:"登录失败"})
}
}
build() {
Column({space:20}) {
TextInput({placeholder:"账号"}).width("90%").onChange(v=>this.account=v)
TextInput({placeholder:"密码"}).type(InputType.Password).width("90%").onChange(v=>this.pwd=v)
Button("提交登录").width("90%").backgroundColor("#007DFF").onClick(()=>this.submitLogin())
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
七、开发规范与使用注意事项
- **@StorageLink 双向绑定:** 适合需要修改数据(登录、设置开关); **@StorageProp 单向绑定:** 纯展示页面(个人中心、首页展示用户),防止意外篡改全局;
- 全局数据统一管理 key 名称,建议在常量文件统一定义,避免字符串写错;
- 复杂对象(用户信息含头像、手机号)也可以存入 AppStorage,直接存 object;
- 数据量大复杂数据不用 AppStorage,优先 RDB 关系型数据库;
- 应用冷启动统一在入口
aboutToAppear从 Preferences 加载全局数据。
更多推荐
所有评论(0)