優先使用 KTX 庫 | MAD Skills

語言: CN / TW / HK

在 Kotlin 中使用 Android 的 Java API 時,您會迅速意識到這樣的做法失去了 Kotlin 語言簡單有趣的特點。與其您親自去編寫這些 API 的 wrapper 和擴充套件函式,不如瞭解一下 Jetpack KTX 庫。目前為止,已有超過 20 個庫擁有對應的 KTX 版本,這些 KTX 庫實現了常用的 Java 版本 API 的功能,包括 Android 平臺 API、ViewModels、SQLite,甚至還有 Play Core。本文會介紹目前可用的 KTX API 並深入其中去分析它們是如何實現的。

如果您比較喜歡觀看視訊,可以 點選這裡

可發現性

為了提高 ktx 功能的可發現性,作為最佳實踐,當某個 ktx 庫可用時,總是匯入並使用它。由於 -ktx 傳遞依賴非 ktx 軟體包,您不需要新增其他軟體包。舉個例子,使用 viewmodel 時,您可以看到兩個軟體包: viewmodel 和 viewmodel-ktx。-ktx 軟體包會包含 Kotlin 的擴充套件:

// 獲取最新 Lifecycle 庫的版本資訊 
// http://developer.android.google.cn/jetpack/androidx/releases/lifecycle
def lifecycle_version = "2.3.1"

// Java 實現
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"

// Kotlin 實現
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

始終匯入 -ktx 軟體包

要使用 Android 平臺 API 的 Kotlin 擴充套件,匯入 core-ktx 軟體包即可。

// 獲取最新 Core 庫的版本資訊
// http://developer.android.google.cn/jetpack/androidx/releases/core3def corektx_version = "1.3.2"

implementation "androidx.core:core-ktx:$corektx_version"

大部分 ktx 功能使用 擴充套件函式 實現的,您可以通過 Android Studio 中的自動完成功能找到它們。

其他功能,像 Color 類上可以使用的 解構操作符過載 功能,可以訪問 KTX 擴充套件程式列表 檢視目前是否可以使用。

平臺 API — core-ktx

core-ktx 為來自 Android 平臺的 API 提供了常用的 Kotlin 功能。

例如,您正在使用 SharedPreferences,當您想去更新一個值,不需要像使用 Java 一樣執行 3 個呼叫,您只需要執行一個呼叫即可:

/* Copyright 2020 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 */

- val editor = sharedPreferences.edit()
- editor.putBoolean(SHOW_DELETED_WORDS_KEY, enable)
- editor.apply()
+ sharedPreferences.edit {
+ putBoolean(SHOW_DELETED_WORDS_KEY, enable)
+ }

在底層,ktx edit 方法和對應 Java 的 API 實現了相同的功能,但 ktx edit 函式 提供了一個更好的預設的資料提交 commit 選項: apply()。和 commit() 不同,apply() 函式會將資料修改非同步寫入磁碟。

 // 來源 http://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core-ktx/src/main/java/androidx/core/content/SharedPreferences.kt;l=39?q=SharedPreferences.kt 
 
 public inline fun SharedPreferences.edit(
     commit: Boolean = false,
     action: SharedPreferences.Editor.() -> Unit
 ) {
     val editor = edit()
     action(editor)
     if (commit) {
        editor.commit()
    } else {
        editor.apply()
    }
}

core-ktx 為處理平臺常用的監聽器提供了更加簡單的方式。例如,您需要在 EditText 的 text 發生變化時觸發一個操作,如果使用 Java,即使您只需要 onTextChanged(),您也必須實現 TextWatcher 介面中所有的函式。core-ktx 建立了 TextWatcher 中對應的方法: doOnTextChangeddoAfterTextChanged 以及 doBeforeTextChanged,在 Kotlin 中,您只需要實現您需要的介面:

 /* Copyright 2020 Google LLC.  
    SPDX-License-Identifier: Apache-2.0 */
 
- editWordView.addTextChangedListener(object : TextWatcher {
-     override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-         handleTextChanged(s)
-     }
-
-     override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-     }
-
-     override fun afterTextChanged(s: Editable) {
-     }
- })
+ editWordView.doOnTextChanged { text, start, count, after -> handleTextChanged(text) }

這樣的變化會帶來許多好處: 程式碼更加簡潔,更好的命名和可空型別的註釋,程式碼的可讀性也得到提高。

AnimatorListenerTransitionListener 也有類似的 API。

實現原理上,doOnTextChanged 是 TextView 的擴充套件函式 -- addTextChangedListener 也是 TextView 的擴充套件函式,doOnTextChanged 為其他 TextWatcher 的函式建立了 空實現

Jetpack API

可用的擴充套件主要提供給 Jetpack API 使用,這裡我會快速介紹一下目前我使用的比較頻繁的擴充套件。

LiveData

很多 LiveData 的功能都是作為擴充套件函式實現的,比如:

例如,使用 livedata-ktxmap 函式,我們不需要呼叫 Transformations.map(livedata) {/*map 函式體*/}livedata-ktx 允許我們通過 Kotlin 慣用的方式直接呼叫 livedData.map

當您觀察一個 LiveData 物件時,您必須實現 Observer 介面。但是使用 lifecycle-ktx 的 observe 函式後,程式碼會變得更加簡潔。如果提示 observe 方法找不到,請確認您已經匯入 androidx.lifecycle.observe

/* Copyright 2020 Google LLC.  
    SPDX-License-Identifier: Apache-2.0 */
 
- wordViewModel.allWords.observe(
-     this,
-     Observer { words ->
-         // 更新 adapter 中快取的 words 副本
-         words?.let { adapter.submitList(it) }
-     }
- )
+ wordViewModel.allWords.observe(owner = this) { words ->
+     // 更新 adapter 中快取的 words 副本
+     words.let { adapter.submitList(it) }
+ }

LiveData 非常適合用於將資料暴露給 UI 使用,因此 lifecycle-livedata-ktx 軟體包提供了兩個簡單的擴充套件函式: Flow.asLiveData()LiveData.asFlow(),分別對 Flow 轉換成 LiveData 以及將 LiveData 轉換成 Flow 予以支援。

Activity / Fragment 和 ViewModel

要構造一個 ViewModel,需要擴充套件 ViewModel 類,如果 ViewModel 有其他依賴,還需要實現 ViewModelProvider.Factory 介面。要例項化 ViewModel,可以使用 viewModels 委託 (詳閱: Kotlin Vocabulary | Kotlin 委託代理): by ViewModels(factory):

/* Copyright 2020 Google LLC.  
   SPDX-License-Identifier: Apache-2.0 */

+ private val wordViewModel: WordViewModel by viewModels {
+     WordViewModelFactory(repository)
+ }
override fun onCreate(savedInstanceState: Bundle?) {
…
-     val viewModelFactory = WordViewModelFactory(repository)
-     val viewModel = ViewModelProvider(this, viewModelFactory).get(WordViewModel::class.java)
}

ActivityFragment 的 -ktx 軟體包都提供了 viewModel 支援。

使用協程時,您可能會在 ViewModel 中啟動一個協程。當 ViewModel 被銷燬時,需要取消協程任務的執行。使用 viewModelScope 後,您不需要實現 CoroutineScope,協程任務的取消會在 viewModel.onCleared() 函式中自動執行。閱讀 相關文章 瞭解 viewModelScope 的來龍去脈。

Room 和 WorkManager

Room 和 WorkManager 通過它們各自對應的 -ktx 軟體包提供了對協程的支援。我們認為有必要更加深入地介紹這部分內容,請繼續關注相應的 "Modern Android Development 技巧" (簡稱為 "MAD Skills") 系列文章。

其他 KTX 模組

不僅僅是 AndroidX,其他一些模組也提供了對 KTX 的支援:

  • Firebase 建立了一些 通用 Kotlin 擴充套件
  • Google Maps 提供了 MapsPlaces 的 ktx 庫;
  • Play Core 有 core-ktx 軟體包,為監控應用內更新狀態提供協程支援。

一旦您開始使用 -ktx 擴充套件,您的程式碼將會從簡潔、易讀和 Kotlin 習慣用語的特性中受益。敬請期待更多方法,並將 Kotlin 和 Jetpack 的優勢應用於您的應用中。