这个系列我做了协程和Flow开发者的一系列文章的翻译,旨在了解当前协程、Flow、LiveData这样设计的原因,从设计者的角度,发现他们的问题,以及如何解决这些问题,pls enjoy it。

LiveData是由Google引入的,作为连接视图(Activity/Fragment)和其ViewModel的一种手段。它就像一个简化的反应式组件(例如RxJava或Kotlin的Flow),也知道视图的生命周期。

随着最近Kotlin的Coroutine和Kotlin的Flow的推出,现在Google推出了一种使用LiveData Coroutine Builder连接Kotlin的Flow和LiveData的方法。

Benefits of using Kotlin’s Coroutine/Flow

使用Kotlin的Coroutine/Flow连接到LiveData的好处是,它可以确保底层组件(如存储库、域层)完全在后台完成。

【译】5 Uses of KTX LiveData Coroutine Builder - 图1

这将有助于克服以下问题:

  • 如果主线程很忙,LiveData的postValue就会丢弃。
  • LiveData的转换功能都是在主线程中完成的。

Pre-requisite

要使用LiveData Coroutine Builder,首先我们需要包含KTX库,例如:

  1. implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"

然后,人们可以使用它,使用:

  1. liveData {
  2. emit(data) // OR
  3. emitSource(liveData)
  4. }
  5. // OR
  6. stateFlow.asLiveData()

让我们来看看LiveData Coroutine Builder的用法吧。

1. Connect Kotlin Coroutine to LiveData

如果我们有一个需要调用的coroutine,以获取一些数据到LiveData,我们可以做以下工作。

  1. val someTypeLiveData: LiveData<SomeType> = liveData {
  2. // get data from is a suspend function
  3. val data = aSuspedFunction()
  4. emit(data)
  5. }

【译】5 Uses of KTX LiveData Coroutine Builder - 图2

一旦LiveData连接到任何观察者,它就会调用并接纳来自suspend函数的数据。

我们也可以确保它是在后台线程上完成的,使用:

  1. val someTypeLiveData: LiveData<SomeType> =
  2. liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
  3. // get data from is a suspend function
  4. val data = aSuspedFunction()
  5. emit(data)
  6. }

2. Connect Kotlin Flow (or StateFlow) to LiveData

以上是一次性的获取。但如果我们有一个流程,其中数据是连续排放的,我们可以使用:

  1. val someTypeLiveData: LiveData<SomeType> =
  2. stateFlow.asLiveData(
  3. viewModelScope.coroutineContext + Dispatchers.IO
  4. )

【译】5 Uses of KTX LiveData Coroutine Builder - 图3

一旦LiveData连接到任何观察者,它就会在stateFlow上待命,发出它的数据。在内部对于asLiveData实际上也是一个LiveData {…}。

  1. public fun <T> Flow<T>.asLiveData(
  2. context: CoroutineContext = EmptyCoroutineContext,
  3. timeoutInMs: Long = DEFAULT_TIMEOUT
  4. ): LiveData<T> = liveData(context, timeoutInMs) {
  5. collect {
  6. emit(it)
  7. }
  8. }

3. Transformation on Background

正如我们之前所分享的,LiveData转换是在主线程上完成的。这使得如果转换逻辑是计算密集型的,这种转换就成了问题。

【译】5 Uses of KTX LiveData Coroutine Builder - 图4

为了把它移到后台,我们必须使用LiveData的switchMap和liveData的coroutine builder,如下图所示。

  1. val liveData: LiveData<String> =
  2. Transformations.switchMap(sourceliveData) {
  3. liveData(viewModelScope.coroutineContext + Dispatchers.IO)
  4. val data = someTranformFunction(it)
  5. emit(data)
  6. }
  7. }

【译】5 Uses of KTX LiveData Coroutine Builder - 图5

4. Connecting Multiple LiveData Source Emission

在这种情况下,我们有多个LiveDatas源数据,我们想控制数据输出的逻辑,我们也可以使用Coroutine Builder。

【译】5 Uses of KTX LiveData Coroutine Builder - 图6

下面是一个非常蹩脚的例子:

  1. liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
  2. emitSource(repository.liveDataSourceA)
  3. delay(2000)
  4. emitSource(repository.liveDataSourceB)
  5. delay(2000)
  6. emitSource(repository.liveDataSourceC)
  7. }

完整示例:https://github.com/elye/demo_android_compose_state_flow_livedata_viewmodel

5. Delay and Keep Coroutine Alive Temporarily

我们在liveData coroutine builder中的一个特殊功能是,它可以被配置为在LiveData不活动的特定时间内保持coroutine的活力。

这在用户改变配置或临时暂停Activity的情况下是非常有用的,而我们希望保持循环程序的活力以完成工作。但是,如果它超过了时间阈值,那么我们就想重新启动整个coroutine操作。

下面是对该条件的准确描述:

liveData构建块作为coroutines和LiveData之间的结构化并发原件。该代码块在LiveData变得活跃时开始执行,当LiveData变得不活跃时,在一个可配置的超时后自动取消。如果它在完成之前被取消,那么如果LiveData再次变得活跃,它将被重新启动。如果它在之前的运行中成功完成,它不会重新启动。注意,只有在自动取消的情况下才会重新启动。如果该块因任何其他原因被取消(例如抛出一个CancellationException),它不会被重新启动。

如果我们看一下代码,我们会看到我们有timeoutInMs,它默认为5s。

  1. @OptIn(ExperimentalTypeInference::class)
  2. public fun <T> liveData(
  3. context: CoroutineContext = EmptyCoroutineContext,
  4. timeoutInMs: Long = DEFAULT_TIMEOUT,
  5. @BuilderInference block: suspend LiveDataScope<T>.() -> Unit
  6. ): LiveData<T> = CoroutineLiveData(context, timeoutInMs, block)

这意味着,当我们把活动(观察LiveData)放在后台,并且活动在暂停/停止时(注意:不是不保留活动),Coroutine将在timeoutInMs的时间内保持活力。

  • 如果超时在coroutine运行结束前完成,coroutine将在Activity恢复活动时重新启动。

【译】5 Uses of KTX LiveData Coroutine Builder - 图7

  • 如果超时没有完成,当Activity恢复活动时,考虑到coroutine没有完成,它将继续进行直到完成。

【译】5 Uses of KTX LiveData Coroutine Builder - 图8

  • 如果coroutine在超时前完成,即使Activity还没有恢复,coroutine也不会被重新启动,而只是发出它的最后一个值。

【译】5 Uses of KTX LiveData Coroutine Builder - 图9

TL; DR

有了LiveData coroutine builder,如果我们想的话,就不能在Kotlin Flow和LiveData之间建立桥梁。这为我们将两种技术结合在一起提供了更大的灵活性,即LiveData观察Android生命周期的能力,以及Kotlin Flor更好的反应式操作和线程处理。

https://medium.com/mobile-app-development-publication/5-uses-of-ktx-livedata-coroutine-builder-48b226bdd591

向大家推荐下我的网站 https://xuyisheng.top/ 专注 Android-Kotlin-Flutter 欢迎大家访问

【译】5 Uses of KTX LiveData Coroutine Builder - 图10