HarmonyOS 鸿蒙Next PersistentStorage数据持久化失败的原因之以及解决方法
1 背景及问题描述 最近在工作之余探索使用ArkTS进行纯血鸿蒙应用的开发,并计划完成一款纯血鸿蒙应用的上架。在开发过程中,在使用PersistentStorage实现登录状态、token的本地持久化过程中,遇到了持久化失败的问题,通过开发者联盟论坛,发现遇到该问题的有很多,很多没有明确的解决方法,参考官方文档与逐步摸索,解决了本次开发过程中持久化失败的问题。
1.1 问题描述 在登录页面完成登录后,应用程序进入登录状态,各个功能使用正常,但当应用后台被杀后,再次打开,仍为未登录状态,状态及token持久化失败。
1.2 开发环境 DevEco Studio版本:5.0.3.910
SDK版本:HarmonyOS 5.0.0 Release SDK,基于OpenHarmony SDK Ohos_sdk_public 5.0.0.71 (API Version 12 Release)
2 解决方法 2.1 持久化失败原因 经过反复阅读官方文档与论坛,定位原因是对PersistentStorage数据持久化的不理解,导致接口调用位置错误或接口使用错误,导致PersistentStorage的持久化运行错,从而导致数据持久化失败。
2.2 解决过程描述 在开始之前,首先附上PersistentStorage的官方文档,方便大家阅读,同时,后面的很多图片将会从该文档中进行引用PersistentStorage官方文档
2.2.1 PersistentStorage与AppStorage执行顺序错误 下图是PersistProp初始化流程,通过该流程可以判断,PersistentStorage的执行与AppStorage(应用级状态存储)是有先后执行顺序的,必须PersistentStorage执行结束后,才可以运行AppStorage,当执行顺序不正确时,AppStorage存储的值会将应用上次退出时持久化的值进行覆盖,从而导致每次打开应用,持久化内容都是失败的。
cke_3696.png
PersistentStorage与AppStorage的执行顺序错误,是本次开发过程中数据持久化的一个原因之一。
2.2.2 PersistentStorage的运行时机错误 PersistentStorage运行的时机也是至关重要的,这是本次开发持久化失败的第二个原因。
根据官方文档,PersistentStorage和UI实例相关联,持久化操作需要在UI实例初始化成功后(即loadContent传入的回调被调用时)才可以被调用,早于该时机调用会导致持久化失败。在本开发中,第一次将PersistentStorage放到了onCreate中,即应用刚创建时便执行持久化,导致了持久化的失败。
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
PersistentStorage.persistProp("isLogin",false)
PersistentStorage.persistProp("userId","")
PersistentStorage.persistProp("username","")
PersistentStorage.persistProp("token","")
PersistentStorage.persistProp("nickname","")
}
在第二次尝试时,将持久化放到了onDestroy中,及当应用销毁时,再执行,想法可以,但是当应用再次启动时,将会首先调用AppStorage,从而导致相关的数据被覆盖,从而导致持久化失败。
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
PersistentStorage.persistProp("isLogin",false)
PersistentStorage.persistProp("userId","")
PersistentStorage.persistProp("username","")
PersistentStorage.persistProp("token","")
PersistentStorage.persistProp("nickname","")
}
2.3 解决后使用方法
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
PersistentStorage.persistProp("isLogin",false)
PersistentStorage.persistProp("userId","")
PersistentStorage.persistProp("username","")
PersistentStorage.persistProp("token","")
PersistentStorage.persistProp("nickname","")
}
代码中在使用如下方式进行状态更新(仅为示例)
//登录页面
@Entry
@Component
struct LoginPage{
[@StorageLink](/user/StorageLink)("isLogin") isLogin:boolean=false;
[@StorageLink](/user/StorageLink)("token") token:string|undefined='';
[@StorageLink](/user/StorageLink)("userId") userId:string|undefined='';
[@StorageLink](/user/StorageLink)("username") username:string|undefined='';
[@StorageLink](/user/StorageLink)("nickname") nickname:string|undefined='';
build() {
Column(){
Button("找回密码",{
type:ButtonType.Capsule
})
.margin({top:10})
.height(40)
.width('100%')
.backgroundColor("#E6A23C")
.onClick(()=>{
httpRequest("/users/loginByHuawei",http.RequestMethod.GET,httpCs,false).then((res:HttpResult)=>{
console.log("请求内容为:"+res.getStatus())
if (res.getStatus()===201) {
// 未注册的处理内容
this.userDomain.setUnionId(unionID)
this.dialogController?.open()
console.log("用户信息获取完成")
}else if (res.getStatus()===200){
this.isLogin=true;
this.userId=res.getHs().get("userId");
this.username=res.getHs().get("username");
this.token=res.getHs().get("token");
this.nickname=res.getHs().get("nickname");
console.log("从appStrong中获取的username为:"+AppStorage.get("username"))
console.log("从this中获取的username为:"+this.username)
router.back()
}
})
}
})
}
}
在非登录页面,使用如下方式实现页面状态的更新
@StorageProp("nickname") nickname:string'';
之所以这样使用,因为 @StorageLink可以将状态更新,实现AppStorage中状态更新,而StorageProp仅是单项的,只可作用于本页面,AppStorage中的状态不会被改变。
3 总结 第一次接触鸿蒙开发,上述错误实属太低级。上述是开发过程中踩的一个大坑,是使用过程中常见的问题,但也会有其它问题导致持久化失败。当然,实现数据持久化,不光有这一种办法,这种办法或许是较为简单的一种,但灵活性可能较差。数据持久化也可使用ArkData(方舟数据管理),其提供了多种API,并实现了多种数据化持久化方式,相比来说更加灵活,但实现过程可能较为复杂。
鸿蒙开发纯小白,欢迎大家指正文字错误之处,也欢迎大家共同交流。