前言
这次持续来搞kt,接着kt开发的100个Tips,没看过上一篇感兴趣的朋友能够看看。juejin.cn/post/724929…
11. 慎用lateinit
运用lateinit有一个条件,那就是有必要保证在运用前进行初始化,否则就会有或许呈现报错。特别是多线程的状况下,会更容易发生错误。
类似Int、Boolean这些根底数据类型,其实在运用的时分能够设置一个默认值。而目标能够用var来润饰
var yourObj: YourObj ?= null
假如想运用延时初始化,也能够尝试by lazy,当然,这里说的慎用并不是说代码中就不能呈现lateinit,详细还需要根据自己的场景。
12. @JvmOverloads
这个注解多用于自界说view的结构办法,假如咱们正常自界说View,需要重写两三个结构办法,而运用@JvmOverloads的话就能很便利的完成自界说View
class MyView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : LinearLayout(context, attrs, defStyleAttr){
......
}
便利是便利,可是运用的时分也不能无脑运用,像有些控件,体系的或许你自界说的view,是有配置defStyleAttr的,这时分你这样运用,defStyleAttr传0,就会导致原本的默认值不收效。
13. kotlin-android-extensions弃用
假如是一些旧项目,或许还会运用kotlin-android-extensions,而kotlin-android-extensions现在是已经被抛弃了。
以前用kae的时分开发就很爽,省去了findviewbyid的操作,所以很多人都喜爱。现在google把它抛弃了,其实也不建议去运用,假如你把运用kotlin-android-extensions的kotlin代码转成java你就会发现其间的端倪。
源码
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
auto_scroll.duration = 3000
}
转后的代码
能够看到它其实是会生成一个HashMap来存,这样就会耗费咱们的内存。所以从优化的视点看仍是不建议直接运用这个办法,并且现在官方也弃用了,假如现在依靠,也会有对应的提示。
能够看出体系推荐咱们用databinding,当然你要是自己想findviewbyid也没啥问题
14. 序列化Parcelable
一般咱们用Java写Parcelable做序列化的时分,往往要写很多代码,而kotlin中现在的版本能够运用@Parcelize 来快速进行序列化。
首要需要在gradle中引进插件
plugins {
......
id("kotlin-parcelize")
}
然后在data中写
@Parcelize
data class TestData(
var number: Int
) : Parcelable
咱们能够直接看它转成java后的代码,会帮咱们生成相应的代码
15. 可变参数的办法
这个就有点像一些脚本语言例如python这些的语法糖,用起来的确挺爽的。
假设我界说一个办法,有3个参数,一个必传参数和两个可传参数
能够看到调用的时分,能够传1个参数,也能够传某个参数,这种写法用起来十分的舒畅。
能够转java看看他内部做了什么
这也能表现kotlin的其间一个优点,它帮你把详细的完成包装起来,让你能用少数的代码去完成之前Java要写较多代码的效果。
16. 快速完成单个办法的回调
假如你想做一些异步回调的操作,无需像java相同先界说一个接口,在kt中能比较便利的完成这个效果
这里就转java看了,原理就是它帮你界说一个接口。
17. 函数作为参数运用
既然上面讲到了函数相关的内容,那趁热打铁再讲讲函数作为参数的运用。
这种状况下java不会有这种语法,所以不会这么写,那会导致一些从java转到kotlin的朋友也不会这么写。
比方说我有一个封装办法add,我的别的两个办法都会调用这个办法,依照咱们写java的写法,会先界说一个办法add,然后再这两个办法里边再去调用这个办法。咱们写了很多年java都是这样写,所以转kt的时分,这种习气也会带过来,可是kt能有别的一种写法,能把函数当成一个目标去传递,例如
这是一个简略的Demo,所以你或许会觉得和别的的写法差不多,没什么用途。其实在一些杂乱的场景里边,这样写能帮你解决掉一些比较难处理的问题,或许说能帮你把一些比较乱的代码变得看上去更合理。
例如我的test1办法里边我要做一些判别,某种场景下要调用aaa办法,某种场景下要调用bbb办法,某种场景下要调用ccc办法,假如用java来写,或许说用java的思路来写,你会传一个场景参数进去,然后在办法里边做if-else操作,例如
fun test1(scene: Int): Int {
if (scene == 1){
return aaa(1,1)
}else if(scene == 2){
return bbb(1,1)
}else {
return ccc(1,1)
}
}
类似这样,我这个Demo比较简略或许不是很明显啊,假如说你这个test1办法里边是一些封装某些功能的办法,它是和事务无关的,你这样写,传的scene是事务相关的,那这个代码是不是就不好看了。而假如你写
fun test1(function: (Int, Int) -> Int): Int {
return function(1, 1)
}
我调用的地方是事务相关的,传aaa进来,bbb进来,ccc进来,都不会影响我里边的功能,你假如今后事务要改动,scene多加了一个类型,也不会影响我这个办法。
再比方我要把这个办法传给别的一个类的目标,我用这个函数作为参数就能直接传,而你用java的办法要完成就比较麻烦。
我说这条tips的意思是,有些在java中习气的写法,你或许转kt后不屑于运用这边的东西,觉得依照java的写法也行,其实是也行,只不过kt供给给你的办法更快。
18. 扩展函数的进阶运用
上一篇也有说到扩展函数,可是也仅仅简略的介绍,其实扩展函数假如用得好的话,对开发效率会有十分大的提高。
例如咱们做dp转px,一般都是写一个东西类dp2px,然后在运用的时去调用这个东西类
fun dip2px(dpValue: Float): Int {
val scale = Resources.getSystem().displayMetrics.density
return (dpValue * scale + 0.5f).toInt()
}
而假如做扩展函数,咱们能够这样写
val Float.dp: Int
get() = dip2px(this)
fun dip2px(dpValue: Float): Int {
val scale = Resources.getSystem().displayMetrics.density
return (dpValue * scale + 0.5f).toInt()
}
然后在调用的时分直接调用
val k: Int = 16f.dp
Log.d("mmp", "$k")
这样写就很便利,能够看看最终的成果
再举个栗子,在kotlin中没有像java相同的三目运算符,所以咱们假如根据一个Boolean类型判别一个View的显示和躲藏的话,一般要怎样写
view.visibility = if (bol) View.VISIBLE else View.GONE
可是总不能每次都写这么长吧,所以能够做个扩展函数
fun View.visibilityByBoolean(bol: Boolean) {
this.visibility = if (bol) View.VISIBLE else View.GONE
}
然后在运用的时分直接调用
val test: LinearLayout = findViewById(R.id.test)
test.visibilityByBoolean(false)
看得出这就比较舒畅了。
所以假如扩展函数用得好的话,是能很大的提高自身的开发效率。那么这里再留下一个问题,扩展函数的原理是什么?这是面试会或许考的常识哦~~~
19. 带?的的判别
由于有时分界说的目标可为空的,假如是一个Boolean?的类型,或许有些人不知如何做判别,比方
能够看到底部会有个错误提示正告你不能直接这样写。
而为了处理这种状况,有些新人会直接写
var bol : Boolean? = true
if (bol!!){
// todo
}
其实这种写法不好。要处理这个问题其实很简略,能够这样写
var bol : Boolean? = true
if (bol == true){
// todo
}
这是一些细节上的处理,像!!的判空,仍是尽量不要乱运用,不要为了图个便利,就逮着一个能用的解法就怼进去。
20. 类型强转
这期最终一条tips来个简略点的,kt比较根底的常识 is 用来判别类型, as 用来强转类型,比方说
val a : Any = 10
if (a is String){
}else {
(a as String).length
}
这样肯定会报错,由于a不是String类型,可是根底数据类型有别的一种转化办法,假如写成这样就不会有问题
val a : Any = 10
if (a is String){
}else {
val result = a.toString().length
Log.d("mmp", "$result")
}
这个栗子不太好,究竟万物都能toString(),假如我换成这样
val a = "c"
val result = a.toInt()
Log.d("mmp", "$result")
会报错吗?会报错,由于能够看源码
public actual inline fun String.toInt(): Int = java.lang.Integer.parseInt(this)
但假如这样写
val a = "c"
val result = a.toIntOrNull()
Log.d("mmp", "$result")
这样就不会呈现强转导致的crash,所以在根底类型转化上,能够用xxxOrNull()来防止呈现强转失败导致的crash,假如是非根底类型,能够先用is判别,再用as强转。