Android KTX   属于 Android Jetpack 的一部分。

Android KTX 是一组包含在 Android Jetpack 及其他 Android 库中的 Kotlin 扩展。KTX 扩展为 Jetpack、Android 平台和其他 API 提供了简洁、惯用的 Kotlin 代码。为此,这些扩展利用了几种 Kotlin 语言特性,包括以下内容:

  • 扩展函数 (Extension functions)
  • 扩展属性 (Extension properties)
  • Lambda 表达式 (Lambdas)
  • 命名参数 (Named parameters)
  • 参数默认值 (Parameter default values)
  • 协程 (Coroutines)

例如,在使用 SharedPreferences 时,必须先 创建一个编辑器,然后才能对偏好设置数据进行修改。编辑完成后,还必须应用或提交这些更改,如下例所示:

sharedPreferences
        .edit()  // create an Editor
        .putBoolean("key", value)
        .apply() // write to disk asynchronously

Kotlin lambda 表达式非常适合此用例。它们允许您通过在创建编辑器后传递一个代码块来执行操作,从而采取更简洁的方法,让代码执行,然后让 SharedPreferences API 以原子方式应用这些更改。

下面是 Android KTX 核心函数 SharedPreferences.edit 的一个示例,它向 SharedPreferences 添加了一个 edit 函数。该函数将可选的 boolean 标志作为其第一个参数,用以指示是提交还是应用更改。它还以 lambda 形式接收要在 SharedPreferences 编辑器上执行的操作。

// SharedPreferences.edit extension function signature from Android KTX - Core
// inline fun SharedPreferences.edit(
//         commit: Boolean = false,
//         action: SharedPreferences.Editor.() -> Unit)

// Commit a new value asynchronously
sharedPreferences.edit { putBoolean("key", value) }

// Commit a new value synchronously
sharedPreferences.edit(commit = true) { putBoolean("key", value) }

调用者可以选择提交还是应用更改。action lambda 本身是 SharedPreferences.Editor 上的一个匿名扩展函数,如其签名所示,它返回 Unit。这就是为什么在该代码块内,您可以直接对 SharedPreferences.Editor 进行操作的原因。

最后,SharedPreferences.edit() 签名包含了 inline 关键字。此关键字告诉 Kotlin 编译器,每次使用该函数时,都应复制并粘贴(即内联)该函数的编译后字节码。这样可以避免每次调用此函数时都为每个 action 实例化一个新类的开销。

这种使用 lambda 传递代码、应用可被覆盖的合理默认值,以及使用 inline 扩展函数将这些行为添加到现有 API 的模式,是 Android KTX 库所提供增强功能的典型代表。

在您的项目中使用 Android KTX

要开始使用 Android KTX,请将以下依赖项添加到您项目的 build.gradle 文件中:

Groovy

repositories {
    google()
}

Kotlin

repositories {
    google()
}

AndroidX 模块

Android KTX 按模块组织,每个模块包含一个或多个包。

您必须在应用的 build.gradle 文件中为每个模块工件包含一个依赖项。请记得在工件名称后追加版本号。您可以在本主题中每个工件对应的部分找到最新的版本号。

Android KTX 包含一个核心模块,该模块为常见的框架 API 和几个特定领域扩展提供了 Kotlin 扩展。

除核心模块外,所有 KTX 模块工件都会替换 build.gradle 文件中的底层 Java 依赖项。例如,您可以将 androidx.fragment:fragment 依赖项替换为 androidx.fragment:fragment-ktx。这种语法有助于更好地管理版本控制,并且不会增加额外的依赖项声明要求。

Core KTX

Core KTX 模块为 Android 框架中常见的库提供扩展。这些库没有需要添加到 build.gradle 中的基于 Java 的依赖项。

要包含此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.core:core-ktx:1.19.0"
}

Kotlin

dependencies {
    implementation("androidx.core:core-ktx:1.19.0")
}

以下是 Core KTX 模块中包含的包列表:

Collection KTX

Collection 扩展包含用于处理 Android 内存高效型集合库(包括 ArrayMapLongSparseArrayLruCache 等)的实用函数。

要使用此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.collection:collection-ktx:1.6.0"
}

Kotlin

dependencies {
    implementation("androidx.collection:collection-ktx:1.6.0")
}

Collection 扩展利用了 Kotlin 的运算符重载来简化集合拼接等操作,如下例所示:

// Combine 2 ArraySets into 1.
val combinedArraySet = arraySetOf(1, 2, 3) + arraySetOf(4, 5, 6)

// Combine with numbers to create a new sets.
val newArraySet = combinedArraySet + 7 + 8

Fragment KTX

Fragment KTX 模块提供了许多简化 Fragment API 的扩展。

要包含此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.8.9"
}

Kotlin

dependencies {
    implementation("androidx.fragment:fragment-ktx:1.8.9")
}

使用 Fragment KTX 模块,您可以使用 lambda 表达式简化 Fragment 事务,例如:

fragmentManager().commit {
   addToBackStack("...")
   setCustomAnimations(
           R.anim.enter_anim,
           R.anim.exit_anim)
   add(fragment, "...")
}

您还可以通过使用 viewModelsactivityViewModels 属性委托,在一行代码中绑定到 ViewModel

// Get a reference to the ViewModel scoped to this Fragment
val viewModel by viewModels<MyViewModel>()

// Get a reference to the ViewModel scoped to its Activity
val viewModel by activityViewModels<MyViewModel>()

Lifecycle KTX

Lifecycle KTX 为每个 Lifecycle 对象定义了一个 LifecycleScope。在此范围内启动的任何协程都会在 Lifecycle 被销毁时取消。您可以使用 lifecycle.coroutineScopelifecycleOwner.lifecycleScope 属性来访问 LifecycleCoroutineScope

要包含此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.11.0"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.11.0")
}

以下示例演示了如何使用 lifecycleOwner.lifecycleScope 异步创建预计算文本:

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val params = TextViewCompat.getTextMetricsParams(textView)
            val precomputedText = withContext(Dispatchers.Default) {
                PrecomputedTextCompat.create(longTextContent, params)
            }
            TextViewCompat.setPrecomputedText(textView, precomputedText)
        }
    }
}

LiveData KTX

使用 LiveData 时,您可能需要异步计算值。例如,您可能希望检索用户的偏好设置并将其提供给 UI。对于这些情况,LiveData KTX 提供了一个 liveData 构建器函数,该函数会调用 suspend 函数并将结果作为 LiveData 对象提供。

要包含此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.11.0"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.11.0")
}

在下面的示例中,loadUser() 是在其他地方声明的挂起函数。您可以使用 liveData 构建器函数异步调用 loadUser(),然后使用 emit() 来发出结果:

val user: LiveData<User> = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

有关将协程与 LiveData 结合使用的更多信息,请参阅将 Kotlin 协程与架构组件结合使用

Navigation 库的每个组件都有其自己的 KTX 版本,这些版本调整了 API,使其更加简洁和符合 Kotlin 习惯。

要包含这些模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.navigation:navigation-runtime-ktx:2.9.8"
    implementation "androidx.navigation:navigation-fragment-ktx:2.9.8"
    implementation "androidx.navigation:navigation-ui-ktx:2.9.8"
}

Kotlin

dependencies {
    implementation("androidx.navigation:navigation-runtime-ktx:2.9.8")
    implementation("androidx.navigation:navigation-fragment-ktx:2.9.8")
    implementation("androidx.navigation:navigation-ui-ktx:2.9.8")
}

使用扩展函数和属性委托来访问目标参数并导航到目的地,如下例所示:

class MyDestination : Fragment() {

    // Type-safe arguments are accessed from the bundle.
    val args by navArgs<MyDestinationArgs>()

    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        view.findViewById<Button>(R.id.next)
            .setOnClickListener {
                // Fragment extension added to retrieve a NavController from
                // any destination.
                findNavController().navigate(R.id.action_to_next_destination)
            }
     }
     ...

}

Palette KTX

Palette KTX 模块为处理调色板提供了符合 Kotlin 习惯的支持。

要使用此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.palette:palette-ktx:1.0.0"
}

Kotlin

dependencies {
    implementation("androidx.palette:palette-ktx:1.0.0")
}

例如,处理 Palette 实例时,您可以使用 get 运算符 ([ ]) 为给定的 target 检索 selected 色样:

val palette = Palette.from(bitmap).generate()
val swatch = palette[target]

Reactive Streams KTX

Reactive Streams KTX 模块允许您从 ReactiveStreams 发布者创建可观察的 LiveData 流。

要包含此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:2.11.0"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.11.0")
}

例如,假设有一个包含少量用户列表的数据库。在应用中,您将数据库加载到内存中,然后在 UI 中显示用户数据。要实现这一点,您可以使用 RxJavaRoom Jetpack 组件可以将用户列表检索为 Flowable。在这种情况下,您还必须在 Fragment 或 Activity 的整个生命周期内管理 Rx 发布者订阅。

但是,使用 LiveDataReactiveStreams,您可以受益于 RxJava 及其丰富的运算符和工作调度功能,同时又能享受 LiveData 的简洁性,如下例所示:

val fun getUsersLiveData() : LiveData<List<User>> {
    val users: Flowable<List<User>> = dao.findUsers()
    return LiveDataReactiveStreams.fromPublisher(users)
}

Room KTX

Room 扩展增加了对数据库事务的协程支持。

要使用此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.room:room-ktx:2.8.4"
}

Kotlin

dependencies {
    implementation("androidx.room:room-ktx:2.8.4")
}

这里有两个 Room 现在使用协程的示例。第一个示例使用 suspend 函数返回 User 对象列表,第二个示例利用 Kotlin 的 Flow 异步返回 User 列表。请注意,使用 Flow 时,您还会收到所查询表中任何更改的通知。

@Query("SELECT * FROM Users")
suspend fun getUsers(): List<User>

@Query("SELECT * FROM Users")
fun getUsers(): Flow<List<User>>

SQLite KTX

SQLite 扩展将 SQL 相关代码封装在事务中,消除了大量样板代码。

要使用此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.sqlite:sqlite-ktx:2.6.2"
}

Kotlin

dependencies {
    implementation("androidx.sqlite:sqlite-ktx:2.6.2")
}

以下是使用 transaction 扩展执行数据库事务的示例:

db.transaction {
    // insert data
}

ViewModel KTX

ViewModel KTX 库提供了一个 viewModelScope() 函数,使您可以更轻松地从 ViewModel 启动协程CoroutineScope 绑定到 Dispatchers.Main,并会在 ViewModel 清除时自动取消。您可以将 viewModelScope() 用作替代,而不必为每个 ViewModel 创建新范围。

要包含此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.11.0"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.11.0")
}

例如,下面的 viewModelScope() 函数启动了一个在后台线程中进行网络请求的协程。库负责处理所有设置和相应的范围清除工作。

class MainViewModel : ViewModel() {
    // Make a network request without blocking the UI thread
    private fun makeNetworkRequest() {
        // launch a coroutine in viewModelScope
        viewModelScope.launch  {
            remoteApi.slowFetch()
            ...
        }
    }

    // No need to override onCleared()
}

WorkManager KTX

WorkManager KTX 提供了对协程的一流支持。

要包含此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "androidx.work:work-runtime-ktx:2.11.2"
}

Kotlin

dependencies {
    implementation("androidx.work:work-runtime-ktx:2.11.2")
}

现在,您可以不再扩展 Worker,而是扩展 CoroutineWorker,它的 API 略有不同。例如,如果您想构建一个简单的 CoroutineWorker 来执行某些网络操作,可以执行以下操作:

class CoroutineDownloadWorker(context: Context, params: WorkerParameters)
        : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result = coroutineScope {
        val jobs = (0 until 100).map {
            async {
                downloadSynchronously("https://www.google.com")
            }
        }

        // awaitAll will throw an exception if a download fails, which
        // CoroutineWorker will treat as a failure
        jobs.awaitAll()
        Result.success()
    }
}

有关使用 CoroutineWorker 的更多信息,请参阅 CoroutineWorker 中的线程处理

WorkManager KTX 还向 OperationsListenableFutures 添加了扩展函数,以挂起当前协程。

以下是一个挂起由 enqueue() 返回的 Operation 的示例:

// Inside of a coroutine...

// Run async operation and suspend until completed.
WorkManager.getInstance()
        .beginWith(longWorkRequest)
        .enqueue().await()

// Resume after work completes...

其他 KTX 模块

您还可以包含 AndroidX 之外的其他 KTX 模块。

Firebase KTX

Android 的一些 Firebase SDK 具有 Kotlin 扩展库,使您能够在应用中使用 Firebase 时编写符合习惯的 Kotlin 代码。有关更多信息,请参阅以下主题:

Google Maps Platform KTX

Google Maps Platform Android SDK 提供了 KTX 扩展,允许您利用多种 Kotlin 语言特性,例如扩展函数、命名参数和默认参数、解构声明和协程。有关更多信息,请参阅以下主题:

Play Core KTX

Play Core KTX 通过向 Play Core 库中的 SplitInstallManagerAppUpdateManager 添加扩展函数,增加了对一次性请求的 Kotlin 协程支持,以及对监控状态更新的 Flow 支持。

要包含此模块,请将以下内容添加到您应用的 build.gradle 文件中:

Groovy

dependencies {
    implementation "com.google.android.play:core-ktx:1.8.1"
}

Kotlin

dependencies {
    implementation("com.google.android.play:core-ktx:1.8.1")
}

以下是状态监控 Flow 的示例:

// Inside of a coroutine...

// Request in-app update status updates.
manager.requestUpdateFlow().collect { updateResult ->
    when (updateResult) {
        is AppUpdateResult.Available -> TODO()
        is AppUpdateResult.InProgress -> TODO()
        is AppUpdateResult.Downloaded -> TODO()
        AppUpdateResult.NotAvailable -> TODO()
    }
}

更多信息

要了解有关 Android KTX 的更多信息,请观看 DevBytes 视频

要报告问题或建议功能,请使用 Android KTX 问题跟踪器