前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >优先使用 KTX 库 | MAD Skills

优先使用 KTX 库 | MAD Skills

作者头像
bennyhuo
发布2021-04-26 12:08:51
1.7K0
发布2021-04-26 12:08:51
举报
文章被收录于专栏:BennyhuoBennyhuo

在 Kotlin 中使用 Android 的 Java API 时,您会迅速意识到这样的做法失去了 Kotlin 语言简单有趣的特点。与其您亲自去编写这些 API 的 wrapper 和扩展函数,不如了解一下 Jetpack KTX 库。目前为止,已有超过 20 个库拥有对应的 KTX 版本,这些 KTX 库实现了常用的 Java 版本 API 的功能,包括 Android 平台 API、ViewModels、SQLite,甚至还有 Play Core。本文会介绍目前可用的 KTX API 并深入其中去分析它们是如何实现的。

如果您比较喜欢观看视频,可以查看下面链接:

https://youtu.be/nKzvYBMdm54

可发现性

为了提高 ktx 功能的可发现性,作为最佳实践,当某个 ktx 库可用时,总是导入并使用它。由于 -ktx 传递依赖非 ktx 软件包,您不需要添加其他软件包。举个例子,使用 viewmodel 时,您可以看到两个软件包: viewmodel 和 viewmodel-ktx。-ktx 软件包会包含 Kotlin 的扩展:

代码语言:javascript
复制
// 获取最新 Lifecycle 库的版本信息 
// https://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 软件包即可。

代码语言:javascript
复制
// 获取最新 Core 库的版本信息
// https://developer.android.google.cn/jetpack/androidx/releases/core
def corektx_version = "1.3.2"

implementation "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 功能。

例如,您正在使用 SharedPreferences,当您想去更新一个值,不需要像使用 Java 一样执行 3 个调用,您只需要执行一个调用即可:

代码语言:javascript
复制
/* 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() 函数会将数据修改异步写入磁盘。

  • 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
代码语言:javascript
复制
// 来源 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 

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 中对应的方法: doOnTextChanged、doAfterTextChanged 以及 doBeforeTextChanged,在 Kotlin 中,您只需要实现您需要的接口:

  • doOnTextChanged https://developer.android.google.cn/reference/kotlin/androidx/core/widget/package-summary#doontextchanged
  • doAfterTextChanged https://developer.android.google.cn/reference/kotlin/androidx/core/widget/package-summary#doaftertextchanged
  • doBeforeTextChanged https://developer.android.google.cn/reference/kotlin/androidx/core/widget/package-summary#dobeforetextchanged
代码语言:javascript
复制
/* 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) }

这样的变化会带来许多好处: 代码更加简洁,更好的命名和可空类型的注释,代码的可读性也得到提高。

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-ktx 的 map 函数,我们不需要调用 Transformations.map(livedata) {/*map 函数体*/},livedata-ktx 允许我们通过 Kotlin 惯用的方式直接调用 livedData.map。

当您观察一个 LiveData 对象时,您必须实现 Observer 接口。但是使用 lifecycle-ktx 的 observe 函数后,代码会变得更加简洁。如果提示 observe 方法找不到,请确认您已经导入 androidx.lifecycle.observe。

  • Observer https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/Observer
代码语言:javascript
复制
/* 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 予以支持。

  • Flow.asLiveData() https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#aslivedata
  • LiveData.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/ViewModel
  • ViewModelProvider.Factory https://developer.android.google.cn/reference/androidx/lifecycle/ViewModelProvider.Factory
  • viewModels https://developer.android.google.cn/reference/kotlin/androidx/activity/package-summary#(androidx.activity.ComponentActivity).viewModels(kotlin.Function0)
代码语言:javascript
复制
/* 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)
}

Activity 和 Fragment 的 -ktx 软件包都提供了 viewModel 支持。

使用协程时,您可能会在 ViewModel 中启动一个协程。当 ViewModel 被销毁时,需要取消协程任务的执行。使用 viewModelScope 后,您不需要实现 CoroutineScope,协程任务的取消会在 viewModel.onCleared() 函数中自动执行。阅读相关文章了解 viewModelScope 的来龙去脉。

  • viewModelScope https://developer.android.google.cn/reference/kotlin/androidx/lifecycle/package-summary#viewmodelscope
  • viewModel.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/packages
  • Maps https://developers.google.cn/maps/documentation/android-sdk/ktx
  • Places https://developers.google.cn/maps/documentation/places/android-sdk/ktx

一旦您开始使用 -ktx 扩展,您的代码将会从简洁、易读和 Kotlin 习惯用语的特性中受益。敬请期待更多方法,并将 Kotlin 和 Jetpack 的优势应用于您的应用中。

点击屏末 | 阅读原文 | 即刻查看 KTX 扩展程序列表


推荐阅读


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Kotlin 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档