Kotlin 在Android開發中那些讓人舒適的地方

前言

目前公司的項目已經全面使用Kotlin,轉換的過程的確不是怎麼讓人舒適,但是讓人欣慰的是結局是讓人滿意的。Kotlin的確可以讓代碼簡潔,安全並且高效。這裏分享一下,在使用Kotlin中那些讓人覺得舒適的地方。

  • 字符模板
  • 空安全
  • 延遲加載
  • 方便易讀的循環
  • 強大易用的迭代器
  • 默認參數
  • DataClass
  • 簡短而強大的標準函數庫
  • 通吃的when(結合密封類會讓代碼更舒適)
  • 擴展
  • 簡單的Bundle 快速的Parcelable
  • 未完待續..

字符模板

開發中難免需要根據多個字段去拼接一條字符串做展示,在過長或者過於複雜的數據邏輯的時候,用Java實現起來都過於冗長。Kotlin 使用 $ 放在變量名的前面去表達字符串中的變量和表達式,從而簡化了這一過程。

    val str = "hello"
    // str length : 5
    print("$str length: {$str.length}")

空安全

在使用Java開發Android的過程中,避免不了大量的空安全判定代碼,介於Kotlin要很好的兼容Java,在這個問題上Kotlin設計一整套新的類型系統(這裏不作研究)來完善優化它。

所有的類型都分爲可空和不可空類型,並且針對不可空類型強制要求初始化,在一開始就讓開發者高標準的、嚴謹的使用變量,是一種規範性的要求。但是可空類型可能會在程序中更廣泛的應用,針對這一點,Kotlin也有Elvis 操作符來進行安全訪問或者避免空值情況,見簡潔代碼。

 

    // 不可空類型(使用前必須初始化)
    var notCanNullInt: Int = 0
    // 可空類型
    var canNullInt: Int? = null
    // 安全訪問
    print("${canNullInt?.toShort()}")
    // 避免空值 爲空給與一個默認值
    val age = canNullInt ?: 18
    // 爲空返回
    val time = canNullInt ?: return

延遲加載

這一點可以說是對不可空類型的更進一步優化,開發中總有一些變量是在某些時機纔會被初始化,而不是類加載的時候就加載。延遲加載是很好的東西,可以省去初始化的成本,在變量真正被需要的時候才被初始化。

    val userInfo: UserInfo by lazy { UserInfo() }
    lateinit var person: InvationPerson

方便易讀的循環

Kotlin有區間的概念,這個概念讓創建循環更加易讀方便。

    // print :0 1 2 3 4 5 6 7 8 9 10
    for (i in 0..10) {
        print("$i ")
    }
    // print :10 9 8 7 6 5 4 3 2 1 0
    for (i in 10 downTo 0) {
        print("$i ")
    }
    // print :0 2 4 6 8 10
    for (i in 0..10 step 2) {
        print("$i ")
    }
    // print :0 1 2 3 4 5 6 7 8 9
    for (i in 0 until 10) {
        print("$i ")
    }
    val map = mapOf("a" to 1, "b" to 2)
    // print :a - 1 b - 2
    for ((key, value) in map) {
        print("$key - $value")
    }

強大易用的迭代器

遍歷集合是基操,對於一些稍微複雜一點的數據邏輯,Java實現起來並不友好。當然後面有了RxJava來進行補救,不過Kotlin做的似乎要更好一點。(這裏就不討論Kotlin的集合框架架構了)

    val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
    
    list.forEach { print(it) }
    // 映射
    val listUp = list.map { it + 2 }
    // 過濾
    val listFilter = list.filter { it % 2 == 0 }
    // asSequence 懶處理 map filter中都存在遍歷操作 asSequence可以將它們合併起來 只存在一次遍歷 提升性能
    val listMore = list.asSequence().map { it + 2 }.filter { it % 2 == 0 }.toList()

asSequence 對提升效率大有裨益,其他的操作就不一一列舉了

默認參數

重載是很比較常見的操作,但是有時候這種方式會出現很多相同的模板代碼。Kotlin的默認參數,可以給參數指定默認值,並且在調用的時候像給變量賦值一樣給參數賦值而不用像Java一樣非要按照順序去傳值。並且因爲具有默認值的原因,所以調用的時候可以根據具體情況傳遞參數,更加靈活、更加易讀和簡潔。

    class Point(val x: Float = 0F, val y: Float = 0F)

    val x = Point(x = 10F)// x 10 y 0
    val y = Point(y = 10F)// x 0 y 10
    val xy = Point(x = 10F, y = 10F)// x10 y10

DataClass

開發中Bean文件是必不可少的,但是Java的Bean文件大部分都是模版代碼,雖然有插件自動生成,但是依然會覺得比較繁瑣,Kotlin可以將這些類申明爲Data類,這些類會默認實現equals(),hashCode(),toString() 和copy() 方法,從幾十行Java代碼簡潔到幾行代碼,Kotlin只用聲明 一個data class

    data class Person(
        val name: String,
        val age: Int,
        val sex: Int
    ){
        //....
    }

簡短而強大的標準函數庫

這是Kotlin提供的函數庫,使用後會簡化不少的樣板代碼。稍微不一樣的地方是它們的thisit各自指向不一樣,以及返回值得不一樣,使用得時候根據具體得情況來就可以了.

run

val str = "a"
val res = str.run{
    // this 指向 "a" it沒有指向
    // 可以直接訪問對象得屬性
    print(length)
    1 // 最後一行返回值爲1
}

let

val str = "a"
val res = str.let{
    // this 指向當前class
    // it 指向a
    print(it.length)
    "let" // 返回值"let"
}

with

val res = with(user){
    // this 指向user it無指向
    println(age)
    println(name)
    "with" // 返回值
}

apply

val str = "a"
val res = a.apply{
    // this指向a it 無指向
    2 // 返回值
}

通吃的when

對於Java的Stwich再熟悉不過,但是它使用起來有比較多的限制,有時候面對複雜的邏輯會顯得乏力。Kotlin的when表達式可以匹配幾乎任何東西(字面值,枚舉,數字,範圍,類型,表達式,甚至函數(kotlin函數至上)) 簡單感受下:

fun whenTest(number: Number?): String {
    return when (number) {
        null, 0 -> "empty"
        1 -> "tiny"
        in 2..5 -> "small"
        is Long -> "big number"
        else -> "unKnow"
    }
}

當然有時候使用when會有一些比較麻煩的事情,比如對else情況的處理,因爲你的程序中明明只有這麼幾種情況,但是你卻不得不寫上關於else的情況處理,這樣的代碼讓人覺得不安心,也降低了可讀性,這個時候可以結合Koltin的密封類來處理,比如對網絡情況的回執,對錯誤的處理,Android對RecyclerView的適配中多中ViewHolder的處理

// 密封類的存在讓整個過程中可能出現的情況更加嚴謹
sealed class NetWorkResult
data class Success(val resJson: String) : NetWorkResult()
data class Failure(val error: Error) : NetWorkResult()
// 代碼更加易讀
fun netWorkTest(result: NetWorkResult) {
    when (result) {
        is Success -> {
            showResult(result.resJson)
        }
        is Failure -> {
            showError(result.error)
        }
    }
}

擴展

擴展可能是最受歡迎的一個特性,因爲它可以讓你少寫很多工具類,並且讓代碼看起來更易讀,更簡潔。比如做一個防止重複點擊的操作。

// 擴展點擊事件屬性(重複點擊時長)
var <T : View> T.lastClickTime: Long
    set(value) = setTag(1766613352, value)
    get() = getTag(1766613352) as? Long ?: 0
// 重複點擊事件綁定    
inline fun <T : View> T.singleClick(time: Long = 800, crossinline block: (T) -> Unit) {
    setOnClickListener {
        val currentTimeMillis = System.currentTimeMillis()
        if (currentTimeMillis - lastClickTime > time || this is Checkable) {
            lastClickTime = currentTimeMillis
            block(this)
        }
    }
}

簡單的Bundle 快速的Parcelable

一開始我並沒有注意到這個特性,因爲項目是組件化開發,在跳轉傳值上都採用了ARouter,但是當我發現Kotlin對這個做的改造的時候還是非常開心~

今年年初我花一個月的時間收錄整理了一套知識體系,如果有想法深入的系統化的去學習的,可以私信我【安卓】,我會把我收錄整理的資料都送給大家,幫助大家更快的進階。


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章