前言

这次持续来搞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
    }

转后的代码

Kotlin开发的100个Tips (二)

能够看到它其实是会生成一个HashMap来存,这样就会耗费咱们的内存。所以从优化的视点看仍是不建议直接运用这个办法,并且现在官方也弃用了,假如现在依靠,也会有对应的提示。

Kotlin开发的100个Tips (二)

能够看出体系推荐咱们用databinding,当然你要是自己想findviewbyid也没啥问题

14. 序列化Parcelable

一般咱们用Java写Parcelable做序列化的时分,往往要写很多代码,而kotlin中现在的版本能够运用@Parcelize 来快速进行序列化。

首要需要在gradle中引进插件

plugins {
    ......
    id("kotlin-parcelize")
}

然后在data中写

@Parcelize
data class TestData(
    var number: Int
) : Parcelable

咱们能够直接看它转成java后的代码,会帮咱们生成相应的代码

Kotlin开发的100个Tips (二)

15. 可变参数的办法

这个就有点像一些脚本语言例如python这些的语法糖,用起来的确挺爽的。

假设我界说一个办法,有3个参数,一个必传参数和两个可传参数

Kotlin开发的100个Tips (二)

能够看到调用的时分,能够传1个参数,也能够传某个参数,这种写法用起来十分的舒畅。
能够转java看看他内部做了什么

Kotlin开发的100个Tips (二)

这也能表现kotlin的其间一个优点,它帮你把详细的完成包装起来,让你能用少数的代码去完成之前Java要写较多代码的效果。

16. 快速完成单个办法的回调

假如你想做一些异步回调的操作,无需像java相同先界说一个接口,在kt中能比较便利的完成这个效果

Kotlin开发的100个Tips (二)

这里就转java看了,原理就是它帮你界说一个接口。

17. 函数作为参数运用

既然上面讲到了函数相关的内容,那趁热打铁再讲讲函数作为参数的运用。

这种状况下java不会有这种语法,所以不会这么写,那会导致一些从java转到kotlin的朋友也不会这么写。

比方说我有一个封装办法add,我的别的两个办法都会调用这个办法,依照咱们写java的写法,会先界说一个办法add,然后再这两个办法里边再去调用这个办法。咱们写了很多年java都是这样写,所以转kt的时分,这种习气也会带过来,可是kt能有别的一种写法,能把函数当成一个目标去传递,例如

Kotlin开发的100个Tips (二)

这是一个简略的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开发的100个Tips (二)

再举个栗子,在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?的类型,或许有些人不知如何做判别,比方

Kotlin开发的100个Tips (二)

能够看到底部会有个错误提示正告你不能直接这样写。
而为了处理这种状况,有些新人会直接写

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强转。