优先使用 KTX 库 | MAD Skills
可发现性
为了提高 ktx 功能的可发现性,作为最佳实践,当某个 ktx 库可用时,总是导入并使用它。由于 -ktx 传递依赖非 ktx 软件包,您不需要添加其他软件包。举个例子,使用 viewmodel 时,您可以看到两个软件包: viewmodel 和 viewmodel-ktx。-ktx 软件包会包含 Kotlin 的扩展:
1// 获取最新 Lifecycle 库的版本信息
2// https://developer.android.google.cn/jetpack/androidx/releases/lifecycle
3def lifecycle_version = "2.3.1"
4
5// Java 实现
6implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
7
8// Kotlin 实现
9implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
始终导入 -ktx 软件包
1// 获取最新 Core 库的版本信息
2// https://developer.android.google.cn/jetpack/androidx/releases/core
3def corektx_version = "1.3.2"
4
5implementation "androidx.core:core-ktx:$corektx_version"
大部分 ktx 功能使用扩展函数实现的,您可以通过 Android Studio 中的自动完成功能找到它们。
其他功能,像 Color 类上可以使用的解构和操作符重载功能,可以访问 KTX 扩展程序列表查看目前是否可以使用。
Color
https://developer.android.google.cn/kotlin/ktx/extensions-list#for_androidgraphicscolor
KTX 扩展程序列表
https://developer.android.google.cn/kotlin/ktx/extensions-list#androidxactivity
平台 API — core-ktx
core-ktx 为来自 Android 平台的 API 提供了常用的 Kotlin 功能。
1/* Copyright 2020 Google LLC.
2 SPDX-License-Identifier: Apache-2.0 */
3
4- val editor = sharedPreferences.edit()
5- editor.putBoolean(SHOW_DELETED_WORDS_KEY, enable)
6- editor.apply()
7+ sharedPreferences.edit {
8+ putBoolean(SHOW_DELETED_WORDS_KEY, enable)
9+ }
在底层,ktx edit 方法和对应 Java 的 API 实现了相同的功能,但 ktx edit 函数提供了一个更好的默认的数据提交 commit 选项: apply()。和 commit() 不同,apply() 函数会将数据修改异步写入磁盘。
ktx edit 函数
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core-ktx/src/main/java/androidx/core/content/SharedPreferences.kt;l=39
1// 来源 https://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
2
3public inline fun SharedPreferences.edit(
4 commit: Boolean = false,
5 action: SharedPreferences.Editor.() -> Unit
6) {
7 val editor = edit()
8 action(editor)
9 if (commit) {
10 editor.commit()
11 } else {
12 editor.apply()
13 }
14}
core-ktx 为处理平台常用的监听器提供了更加简单的方式。例如,您需要在 EditText 的 text 发生变化时触发一个操作,如果使用 Java,即使您只需要 onTextChanged(),您也必须实现 TextWatcher 接口中所有的函数。core-ktx 创建了 TextWatcher 中对应的方法: doOnTextChanged、doAfterTextChanged 以及 doBeforeTextChanged,在 Kotlin 中,您只需要实现您需要的接口:
doOnTextChanged
https://developer.android.google.cn/reference/kotlin/androidx/core/widget/package-summary#doontextchangeddoAfterTextChanged
https://developer.android.google.cn/reference/kotlin/androidx/core/widget/package-summary#doaftertextchangeddoBeforeTextChanged https://developer.android.google.cn/reference/kotlin/androidx/core/widget/package-summary#dobeforetextchanged
1/* Copyright 2020 Google LLC.
2 SPDX-License-Identifier: Apache-2.0 */
3
4- editWordView.addTextChangedListener(object : TextWatcher {
5- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
6- handleTextChanged(s)
7- }
8-
9- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
10- }
11-
12- override fun afterTextChanged(s: Editable) {
13- }
14- })
15+ editWordView.doOnTextChanged { text, start, count, after -> handleTextChanged(text) }
这样的变化会带来许多好处: 代码更加简洁,更好的命名和可空类型的注释,代码的可读性也得到提高。
AnimatorListener 和 TransitionListener 也有类似的 API。
实现原理上,doOnTextChanged 是 TextView 的扩展函数 -- addTextChangedListener 也是 TextView 的扩展函数,doOnTextChanged 为其他 TextWatcher 的函数创建了空实现。
AnimatorListener
https://developer.android.google.cn/reference/kotlin/androidx/core/animation/package-summary#(android.animation.Animator).addListener(kotlin.Function1,%20kotlin.Function1,%20kotlin.Function1,%20kotlin.Function1)TransitionListener
https://developer.android.google.cn/reference/kotlin/androidx/core/transition/package-summary#(android.transition.Transition).addListener(kotlin.Function1,%20kotlin.Function1,%20kotlin.Function1,%20kotlin.Function1,%20kotlin.Function1)doOnTextChanged
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core-ktx/src/main/java/androidx/core/widget/TextView.kt;l=42?q=doOnTextChanged空实现
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core-ktx/src/main/java/androidx/core/widget/TextView.kt;l=65
Jetpack API
可用的扩展主要提供给 Jetpack API 使用,这里我会快速介绍一下目前我使用的比较频繁的扩展。
LiveData
很多 LiveData 的功能都是作为扩展函数实现的,比如:
map
https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#map
switchMap
https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#switchmap
distinctUntilChanged
https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#distinctuntilchanged
distinctUntilChanged 源码
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/Transformations.kt;l=35
当您观察一个 LiveData 对象时,您必须实现 Observer 接口。但是使用 lifecycle-ktx 的 observe 函数后,代码会变得更加简洁。如果提示 observe 方法找不到,请确认您已经导入 androidx.lifecycle.observe。
Observer
https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/Observer
1/* Copyright 2020 Google LLC.
2 SPDX-License-Identifier: Apache-2.0 */
3
4- wordViewModel.allWords.observe(
5- this,
6- Observer { words ->
7- // 更新 adapter 中缓存的 words 副本
8- words?.let { adapter.submitList(it) }
9- }
10- )
11+ wordViewModel.allWords.observe(owner = this) { words ->
12+ // 更新 adapter 中缓存的 words 副本
13+ words.let { adapter.submitList(it) }
14+ }
LiveData 非常适合用于将数据暴露给 UI 使用,因此 lifecycle-livedata-ktx 软件包提供了两个简单的扩展函数: Flow.asLiveData()、LiveData.asFlow(),分别对 Flow 转换成 LiveData 以及将 LiveData 转换成 Flow 予以支持。
Flow.asLiveData()
https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#aslivedataLiveData.asFlow()
https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#asflow
Activity / Fragment 和 ViewModel
要构造一个 ViewModel,需要扩展 ViewModel 类,如果 ViewModel 有其他依赖,还需要实现 ViewModelProvider.Factory 接口。要实例化 ViewModel,可以使用 viewModels 委托 (详阅: Kotlin Vocabulary | Kotlin 委托代理): by ViewModels(factory):
ViewMode
https://developer.android.google.cn/reference/androidx/lifecycle/ViewModelViewModelProvider.Factory
https://developer.android.google.cn/reference/androidx/lifecycle/ViewModelProvider.FactoryviewModels
https://developer.android.google.cn/reference/kotlin/androidx/activity/package-summary#(androidx.activity.ComponentActivity).viewModels(kotlin.Function0)
1/* Copyright 2020 Google LLC.
2 SPDX-License-Identifier: Apache-2.0 */
3
4+ private val wordViewModel: WordViewModel by viewModels {
5+ WordViewModelFactory(repository)
6+ }
7override fun onCreate(savedInstanceState: Bundle?) {
8…
9- val viewModelFactory = WordViewModelFactory(repository)
10- val viewModel = ViewModelProvider(this, viewModelFactory).get(WordViewModel::class.java)
11}
使用协程时,您可能会在 ViewModel 中启动一个协程。当 ViewModel 被销毁时,需要取消协程任务的执行。使用 viewModelScope 后,您不需要实现 CoroutineScope,协程任务的取消会在 viewModel.onCleared() 函数中自动执行。阅读相关文章了解 viewModelScope 的来龙去脉。
viewModelScope
https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#viewmodelscopeviewModel.onCleared() https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/ViewModel#oncleared 相关文章
https://medium.com/androiddevelopers/easy-coroutines-in-android-viewmodelscope-25bffb605471
Room 和 WorkManager
Room 和 WorkManager 通过它们各自对应的 -ktx 软件包提供了对协程的支持。我们认为有必要更加深入地介绍这部分内容,请继续关注相应的 "Modern Android Development 技巧" (简称为 "MAD Skills") 系列文章。
其他 KTX 模块
不仅仅是 AndroidX,其他一些模块也提供了对 KTX 的支持:
Firebase 创建了一些通用 Kotlin 扩展;
Google Maps 提供了 Maps 和 Places 的 ktx 库;
Play Core 有 core-ktx 软件包,为监控应用内更新状态提供协程支持。
通用 Kotlin 扩展
https://firebase.google.cn/docs/reference/kotlin/packagesMaps
https://developers.google.cn/maps/documentation/android-sdk/ktxPlaces
https://developers.google.cn/maps/documentation/places/android-sdk/ktx
推荐阅读