1. 程式人生 > >KTX 和 Kotlin android extension 都到底是個啥?

KTX 和 Kotlin android extension 都到底是個啥?

1. KTX是什麼

A set of Kotlin extensions for Android app development. The goal of Android KTX is to make Android development with Kotlin more concise, pleasant, and idiomatic by leveraging the features of the language such as extension functions/properties, lambdas, named parameters, and parameter defaults. It is an explicit goal of this project to not add any new features to the existing Android APIs.

Google翻譯如下:

一套用於Android應用開發的Kotlin擴充套件。 Android KTX的目標是通過利用語言的功能(如擴充套件函式/屬性,lambdas,命名引數和引數預設值),使Kotlin的Android開發更簡潔,愉快和慣用。 此專案的明確目標是不向現有Android API新增任何新功能。

到這裡,KTX的原理也清楚了,就是利用了Kotlin的一些語法特性。

但是目前這個專案很久沒有更新了,而且處於 1.0.0-alpha1,期待1.0穩定版的到來。

同時,JakeWharton 也在呼籲大家加入到這個專案中來,一起貢獻程式碼,

官網舉例如下:

Kotlin:

val uri = Uri.parse(myUriString)

Kotlin with Android KTX:

val uri = myUriString.toUri()

Kotlin:

sharedPreferences.edit()
    .putBoolean("key", value)
    .apply()

Kotlin with Android KTX:

sharedPreferences.edit {
    putBoolean("key", value)
}

Kotlin:

val pathDifference = Path(myPath1).apply {
    op(myPath2, Path.Op.DIFFERENCE)
}

canvas.apply {
  val checkpoint = save()
  translate(0F, 100F)
  drawPath(pathDifference, myPaint)
  restoreToCount(checkpoint)
}

Kotlin with Android KTX:

val pathDifference = myPath1 - myPath2

canvas.withTranslation(y = 100F) {
    drawPath(pathDifference, myPaint)
}

Kotlin:

view.viewTreeObserver.addOnPreDrawListener(
    object : ViewTreeObserver.OnPreDrawListener {
        override fun onPreDraw(): Boolean {
            viewTreeObserver.removeOnPreDrawListener(this)
            actionToBeTriggered()
            return true
        }
    })

Kotlin with Android KTX:

view.doOnPreDraw {
     actionToBeTriggered()
}

API如下,都以AndroidX開頭,獨立更新,更新速度大於Android的SDK,以後可能會直接加入到Android Support Library中

2. Kotlin Android Extensions是什麼

Kotlin Android Extensions 是Kotlin官方推出的一個外掛,提高android開發體驗的一個東西

主要有以下功能:

1. View Binding

每個Android開發人員都熟悉findViewById()函式。 毫無疑問,它是潛在錯誤和令人討厭的程式碼的來源,難以閱讀和支援。 雖然有幾個庫可以提供此問題的解決方案,但這些庫需要為每個公開的View註釋欄位。

Kotlin Android Extensions外掛允許我們獲得與其中一些庫相同的體驗,而無需新增任何額外的程式碼。

實質上,這允許以下程式碼:

// Using R.layout.activity_main from the 'main' source set
import kotlinx.android.synthetic.main.activity_main.*

class MyActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // Instead of findViewById<TextView>(R.id.textView)
        textView.setText("Hello, world!")
    }
}

這裡textview作為Activity的一個擴充套件屬性,它和在activity_main.xml中宣告的具有相同型別(即TextView型別)。

對其原理感興趣的,可以反編譯這個成Java檔案,然後檢視其實現原理,其實其內部有一個SparseArray來維護所有的view。

⚠️注意:其實Kotlin Android Extensions是Kotlin外掛的一部分,所以其實要使用Kotlin Android Extensions,不需要安裝額外的外掛,要做的只是啟用它(當然前提是,你已經使用了kotlin的gradle外掛),即在module的build.gradle中加入:

apply plugin: 'kotlin-android-extensions'

2. LayoutContainer Support

LayoutContainer和下面的 Parcelable目前都處於實驗階段,不建議在生產專案中使用,如果要啟用,可在build.gradle新增如下:

androidExtensions {
    experimental = true
}

Android Extensions 外掛支援不同種類的container,常見的如Activity,Fragment,View,但是可以將任何實現了LayoutContainer介面的類轉換成container,如下程式碼中在ViewHolder中使用:

import kotlinx.android.extensions.LayoutContainer

class ViewHolder(override val containerView: View) : ViewHolder(containerView), LayoutContainer {
    fun setup(title: String) {
        itemTitle.text = "Hello World!"
    }
}

3. Flavor support

4. View Caching

呼叫findViewById()會導致緩慢,尤其是在View的層級很大時,所以Android Extensions 外掛檢視使用container來最小化地呼叫findViewById(),在下例中,findViewById()只被呼叫了一次:

class MyActivity : Activity()

fun MyActivity.a() { 
    textView.text = "Hidden view"
    textView.visibility = View.INVISIBLE
}

但是在下面這種情況,就不會再使用快取的View:

fun Activity.b() { 
    textView.text = "Hidden view"
    textView.visibility = View.INVISIBLE
}

5. 更改View的快取策略

可以對container中View的快取策略進行全域性的,或者僅當前類去修改,可選擇的快取方式有:HASH_MAP,SPARSE_ARRAY,NONE。以前預設是HASH_MAP,現在預設好像改成了SPARSE_ARRAY

6. Parcelable序列化

使用方式如下:

import kotlinx.android.parcel.Parcelize

@Parcelize
class User(val firstName: String, val lastName: String, val age: Int): Parcelable

使用要求,所有序列化的引數要寫在主建構函式中,

也可以自定義序列化邏輯

支援的序列化型別:

upported Types

@Parcelize supports a wide range of types:

  • Primitive types (and its boxed versions);
  • Objects and enums;
  • StringCharSequence;
  • Exception;
  • SizeSizeFBundleIBinderIInterfaceFileDescriptor;
  • SparseArraySparseIntArraySparseLongArraySparseBooleanArray;
  • All Serializable (yes, Date is supported too) and Parcelable implementations;
  • Collections of all supported types: List (mapped to ArrayList), Set (mapped to LinkedHashSet), Map (mapped to LinkedHashMap);
    • Also a number of concrete implementations: ArrayListLinkedListSortedSetNavigableSetHashSetLinkedHashSetTreeSetSortedMapNavigableMapHashMapLinkedHashMapTreeMapConcurrentHashMap;
  • Arrays of all supported types;
  • Nullable versions of all supported types.