行业知识
鸿蒙问题之CustomDialog后持久化@state数据崩溃
2026-11-06 05:01:26
来源:互联网转载
开发需���:有一个字符串数组,可以通过弹框编辑其中的某个字符串,编辑完成后更新数组并持久化这个数组。
这个需求算是很简单,很常见的需求了。但是,开发过程中却遇到了一个不小的难题。
我的数组内容需要在组件中显示,数据更新,页面刷新。所以,用@state装饰器修饰数组。
然后,点击某个字符串内容弹出customDialog,用户修改,确认后将修改的字符串回传,同时,修改数组的内容,持久化数组。一番操作猛如虎,结果一看直接崩溃
而且这个崩溃从以上日志是真看不出来为啥。不断的删减代码发现一个官方问题。@state修饰的属性,在customDialog回调中利用用户首选项持久化会崩溃,至于为啥,估计也就官方知道。
结果有了,贴一下我的崩溃示例代码
import Prompt from '@system.prompt'import dataPreferences from '@ohos.data.preferences'@Entry@Componentstruct Index { @State currentTitle: string = '点击我' //需要持久化的数据 @State dataArray: string[] = ['654','357','65456','35723'] private templateDataManager = new BarrageTemplateModel()//自定义弹框 editDialogController: CustomDialogController = new CustomDialogController({ builder: CustomEditDialog({ confirm: this.onConfirm.bind(this), currentTitle:$currentTitle }), autoCancel: false, alignment: DialogAlignment.Center, offset: { dx: 0, dy: -20 }, gridCount: 4, customStyle: false }) //弹框修改完成回调 onConfirm() { this.dataArray.splice(0,1) //这里会导致崩溃 this.templateDataManager.saveTemplateData(getContext(this),'kUserTemplateKey_HanHua',copy) } build() { Row() { Column() { Text(this.currentTitle) .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { //这样直接操作,不牵扯dialog就不崩溃 // this.dataArray.splice(0,1) // this.templateDataManager.saveTemplateData(getContext(this),'kUserTemplateKey_HanHua',this.dataArray) // Prompt.showToast({message:'点击了'}) //这样会崩溃 if (this.editDialogController != undefined) { this.editDialogController.open() } }) } .width('100%') } .height('100%') }}//弹出框@CustomDialogstruct CustomEditDialog { @Link currentTitle: string private tempTitle: string = '' controller: CustomDialogController cancel: () => void confirm: () => void build() { Column() { TextArea({text: this.currentTitle}) .backgroundColor(0xffffff) .fontColor(Color.Black) .fontSize(20) .width('100%') .height(200) .margin(20) .onChange((value: string) => { //显示键盘 if (value) { this.tempTitle = value; } }) Divider() .opacity(0.5) .width('100%') .color('#D3D3D3') Row() { Text('取消') .backgroundColor(0xffffff) .fontColor(Color.Black) .fontSize(20) .margin(10) .height('100%') .width('45%') .textAlign(TextAlign.Center) .onClick(() => { this.controller.close() this.cancel() }) Divider() .vertical(true) .color('#D3D3D3') Text('确定') .backgroundColor(0xffffff) .fontColor(Color.Black) .fontSize(20) .margin(10) .width('45%') .height('100%') .textAlign(TextAlign.Center) .onClick(() => { this.currentTitle = this.tempTitle this.controller.close() this.confirm() }) } .justifyContent(FlexAlign.SpaceEvenly) .width('100%') .height(60) } }}//存储数据的类class BarrageTemplateModel { saveTemplateData(context: Context,key: string, hanHuaArray: string[]) { console.log('存储用户持久化存储的模版:000='+hanHuaArray.toString()) dataPreferences.getPreferences(context,"PREFERENCE_KEY",(err,preference) =>{ if (err) { console.log('存储用户持久化存储的模版:err1='+err) return } console.log('存储用户持久化存储的模版:success1=') preference.put(key,hanHuaArray,(err) =>{ if (err) { console.log('存储用户持久化存储的模版:err2='+err) return } console.log('存储用户持久化存储的模版:success2=') preference.flush((err) => { console.log('存储用户持久化存储的模版:success3=') if (err) { console.log('存储用户持久化存储的模版:err3='+err) return } console.log('存储用户持久化存储的模版:success4=') console.log('存储用户持久化存储的模版:'+hanHuaArray.toString()) }) }) }) }} 查了不少资料,一开始认为是不是因为用户首选项不支持字符串数组,后来看文档是支持的。
然后,认为是不是因为回调的bind(this),但是不添加bind(this)又会导致回调中的this不是当前组件,访问不到属性。
直到后来注意到我的数组用了@state修饰,去掉后果然不崩溃了。但是我的组件中又需要这个数组用@state修饰。进退两难。。。。
最后只能来个曲线救国,我持久化的数据不直接操作@state的对象,而是持久化copy出来新的一份,就不崩溃了,如下
//弹出框的回调方法 onConfirm() { //假设这是对数组进行操作了 this.dataArray.splice(0,1) //回调中我将dataArray复制存储在copy中 const copy = this.dataArray.map( num => num ) //持久化copy数据,不操作dataArraythis.templateDataManager.saveTemplateData(getContext(this),'kUserTemplateKey_HanHua',copy) } 这个操作(复制一份,持久化复制的内容)真的辣眼睛,但是这样确实不崩溃了,值得一提的是:如果你直接const copy = this.dataArray也是不行的,除非复制出来新的一块内存。这个问题估计官方会修复,而且这个操作也太常见了。。。。
上一篇:硬件服务器怎么选?