使用HarmonyOS4+ArkUI+Stage模型进行开发的翻译软件,目前只是半成品,代码写的很挫。记录一下开发过程中踩过的坑。
项目地址:
github github.com/huangyuanlo...
码云项目是从github导入的,偶尔会忘记同步
冻屏、黑屏、假死
运行环境是MetaPadPro 2019 鸿蒙4.0.0,使用api9+stage模型开发,运行在模拟器上正常,但是运行在该设备上出现冻屏现象,页面轮播图无法轮播,滑动组件无法发滑动,就像卡在了这一帧上一样。点击输入框键盘能弹出,但页面是黑的。可以通过锁屏、解锁或者音量键刷新页面。
感觉上就是屏幕不会主动刷新,需要按物理键让屏幕刷新一次似的。
询问过朋友后发现,这个现象只会出现在麒麟系列芯片的手机或平板上,看到论坛也有人咨询相同的问题。向官方提工单后官方回复是已知问题,将会在HarmonyOS next系统中修复
如果只是自己写着玩,可以安装 scrcpy 将屏幕内容同步到电脑上,在电脑上操作是没有问题的。
如果是公司用,建议咨询鸿蒙运营,成为合作伙伴,直接上HarmonyOS Next进行开发。或者降低api版本。
PersistentStorage和@StorageLink
项目中有些设置需要持久化存储,于是选择了PersistentStorage和@StorageLink方式进行存储,大致如下
TypeScript
export class User {
constructor(name: string, age: number) {
this.name = name
this.age = age
}
name: string
age: number
}
PersistentStorage.PersistProp<User>('user', new User('xuan',18))
@Entry
@Component
struct Tmp {
@StorageLink('user') user: User = new User('xuan', 18)
build() {
Text(`${this.user.name} : ${this.user.age}`)
}
}
当我第一运行的时候,页面显示正常,Text显示的内容是xuan : 18
但是当我重新打开应用(不是重新编译,就是简单的在设备上关掉应用然后点击桌面图标打开应用)的时候,Text显示内容是 undefined : undefined
打上断点发现重新打开应用的时候 user
是一个字符串类型,值为 {'name':'xuan','age':18},但字符串对象没有name和age属性,所以显示了 undefined.
看到文档中有写 developer.harmonyos.com/cn/docs/doc...
AppStorage的属性向PersistentStorage中持久化的允许的类型是:
number,string,boolean,enum基础类型。
Object中可序列化的属性。
不允许undefined和null。
但同样的,在指南中同样有PersistentStorage描述 developer.harmonyos.com/cn/docs/doc...
PersistentStorage允许的类型和值有:
number, string, boolean, enum 等简单类型。
可以被JSON.stringify()和JSON.parse()重构的对象。例如Date, Map, Set等内置类型则不支持,以及对象的属性方法不支持持久化。
看到论坛有同样的求助,有开发者回复说他是将对象转成字符串保存的,使用的时候再parse一下。
剪贴板 pasteboard.getSystemPasteboard()
在使用剪贴板时需要先创建剪贴板数据, 创建方法如下
typescript
createData(mimeType: string, value: ValueType): PasteData
createRecord(mimeType: string, value: ValueType):PasteDataRecord
第一个参数含义为:自定义数据的MIME类型。 文档中 鸿蒙开发api参考 中写的示例
typescript
import pasteboard from '@ohos.pasteboard';
let dataXml = 'Hello World';
let pasteDataRecord = pasteboard.createRecord('app/xml', dataXml);
实际中发现时不能使用这自定义的app/xml
值,会崩溃,只能使用pasteboard中预定义的MIME类型
对象属性从有值变为空,应用会崩溃
typescript
@Entry
@Component
struct PlayGround {
@State people:People = new People()
private log(log:string):boolean{
console.error(`---------${log}---------`)
return true
}
build(){
Column() {
if(this.people){
Text(`姓名: ${this.people.name} 年龄:${this.people.age}`)
if(this.people.address){
if(this.log('address 有值')){
Text( `地址: ${this.people.address.name} 邮编:${this.people.address.zipCode}`)
}
else{
Text('address 为空 内部')
}
}else{
if(this.log('address 为空 最外层')){
Text('address 为空 最外层')
}
}
}
Button('网络请求返回一个有地址的对象').onClick(()=>{
let tmpPeople = new People()
let tmpAddress = new Address()
tmpAddress.name = '测试地址'
tmpAddress.zipCode = -1000
tmpPeople.address = tmpAddress
tmpPeople.age = 10
tmpPeople.name = '有地址'
this.people = tmpPeople
})
Button('网络请求返回一个没有地址的对象').onClick(()=>{
let tmpPeople = new People()
tmpPeople.age = 10
tmpPeople.name = '没有地址'
this.people = tmpPeople
})
}.margin({top:48})
}
}
class Address{
zipCode:number
name:string
}
class People{
name:string
age:number
address :Address
}
很简单的页面,展示对象属性, 刚开始运行,一切正常。点击返回有地址的对象,页面正常刷新并且展示。然后点击返回没有地址的对象,这时候会崩溃。 日志指向了 Text( 地址: ${this.people.address.name} 邮编:${this.people.address.zipCode}
)
说是不能从undefined对象中读取name属性
具体可以看这里:开发这论坛
规避方案:我有一个朋友,尝试出了使用 ?.
来规避的方法。 取对象属性除了要用if判断来控制渲染之外,需要用 ?.
来取值,防崩溃,将上面的代码修改为 Text( 地址: ${this.people.address?.name} 邮编:${this.people.address?.zipCode}
) 应用不会崩溃,这个对象也不会渲染在页面上
但根据文档描述,既然if条件不成立,下面的Text组件就不应该被渲染,也不应该读取address的name属性。同样提工单,回复说是双框架问题,将在HarmonyOS Next版本解决
需要注意的是,文档上写的被状态管理装饰器修饰的变量,基本上都不支持any、undefined、null值,但实际写代码的过程中是没有校验的,目前来看即使是这些类型或者值,也是没什么大问题的,但还是建议大家按文档写,有问题咨询相关技术人员或者论坛、提工单。
以上