一,app运行,debug版本没有问题,release出问题
1,针对这个问题,一般会去考虑 代码混淆 问题,而这次遇到的却是由于getString()引起的类型异常。
一个简单的接口请求,之前处理H 字段,一直是 jsonObject.getString(“H”),由于之前H字段一直传的是 String类型,所以都没出错。突然,一个接口,H字段传了 Int 进来,就会抛出一个类似于 “H” not a String之类的异常,最要命的是,debug版本是不会显示出来这个问题的,请求正常,但release就会请求出错。
解决方法 :使用安全的 optString()
思考:本次问题解决是用 optString替代getString就解决了。看似简单随意,但作为受害者来说,确实有所感受-类型安全很重要。先不谈拿到环境,复现的成本,这次开发是在一个基线项目的基础上进行开发的,而这个问题的是在一个自定义的Gson转换器里,就是retrofit设置代理时 add的转换器,这意味这个问题影响几乎整个app的网络请求,特别是基线产品,当处理一些不够“规范”的定制接口,这就完蛋了。之前我还觉得kotlin的空安全貌似没必要,现在想来,还是自己接触的太少,没经历空指针异常的毒打。线程安全,类型安全等等,甚至是一些优化,不能因为没遇到,就固执己见,不去思考
二,对于安卓,事件的理解。
问题:一个外界扫码枪,扫描二维码,通过keyevent事件拿到信息,被输入框的onKeyDown截胡了
这就涉及事件分发流程和处理流程问题。
安卓事件的分发是由 外层的容器,decview->Activity->控件
而事件处理是刚好反过来 ,所以控件的onkeydown事件是在activity之前的。
由于之前的不理解,我就想在分发的时候拿到数据,然后返回 false ,结果是没截胡了(扫码结果直接在输入框显示,触发一系列连锁反应),但直接把本页面所有的keyevent给干掉了。说到底,还是对这个流程不清楚,导致乌龙。最后的处理是,让输入框的onkey事件直接返回false,不处理。这里是特殊的,我们的场景是不需要键盘输入,而是用textview画了几个按钮。不过,只要知道流程,解决方案就就会有的。
三,object类:实现编号与字段名的转换
项目中,经常会遇到一些编号与字段名称的转换工作,例如 01 表示浙江省, 02表示其他省之类的,如果我们每次需要转换时,都写一个 when 表达式来转换,那代码将变得十分多,因为这样的转换工作会多次用到,且when表达式本身带来的代码量就很大,所以我们可以用kotlin写一个object工具类来存放一些map变量(之前我就知道转换要用map,比较快捷方便,但是我的map是在activity里的,没有放到工具类的,所以格局小了),eg Object aa{
val Map = mutableMapOf<String, String>().apply {
put(“绿”,“1”)
put(“黄”,“188”)
put( “红”,“381”)
}.withDefault { “1889” }
}
。当然,Object 也可以当作静态工具类来储存一些临时的变量,对象啥的,例如一个场景是学生报道登记,学生拿着一张临时表要去好几个地点填信息,最后再把表交给班长,我们可以用intent传这张表对象,在多个activity里那啥,但是直接写一个静态对象,也是不错的选择Z(内存够用),类似于java的静态对象(被放到了方法区里)。
以上说的转换的例子,由于之前没意识到工具类的编写,就是在多个地方进行 粘贴复制,导致代码质量简直不能看。并不是能用就行,不要固执,写最优的代码
其实上面说的,就是 我们在开发过程中,要学会写工具类,用来复用,储存一些常量以及相应的方法,或者储存临时对象。在kotlin是object,在java就是单例对象。
java储存常量之前用的是interface,因为自带public final static 。
object类:对象声明,伴生对象,对象表达式
对象声明:和我们的静态对象类似,它自己实现了单例,kotlin调用可以直接a.fun(),java调用 a.INSTANCE.fun(),一般用来编写工具类,就如上面说的 转换,存放临时变量之类
注意:
kotlin自带的注解:@JvmStatic或者@JvmField,这样就可以和kotlin调用保持一致。
@JvmStatic既可以修饰属性,也可以修饰方法;而@JvmField只能修饰属性
伴生对象:相当于java的静态内部类,和对象声明的区别,就是不暴露出去(个人理解)
对象表达式:
对象表达式常用来作为匿名内部类的实现
private val callBack = object : CallBack {
override fun onSuccess() {}
override fun onFailure() {}
}
// 通过对象表达式实现点击事件回调
btn.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
TODO(“Not yet implemented”)
}
})