Android 中的 LiveDataScope 与 ViewModelScope

LiveDataScope vs ViewModelScope in Android

我在这里阅读如何使用协程 https://developer.android.com/topic/libraries/architecture/coroutines。让我感到困惑的是 LiveDataScopeViewModelScope 之间的区别。听起来 ViewModelScope 会自动处理生命周期,您可以在块中进行网络请求。当从服务器接收到数据时,post 的值变为 livedata。但是当我继续阅读时,还有另一个关于 LiveDataScope 的主题,这对我来说似乎是多余的,因为您已经可以通过使用 ViewModelScopelivedata 来实现相同的结果。这两者之间的主要区别是什么?我应该在什么时候选择使用一个而不是另一个?

名副其实:

A ViewModelScope is defined for each ViewModel in your app. Any coroutine launched in this scope is automatically canceled if the ViewModel is cleared.

这意味着您可以在 ViewModel 范围内的协程中执行一些任务(如连续处理)。优点是您不必再关心何时停止 ViewModel 以停止您的协程(这在处理诸如 java 线程之类的全局事物时是一个很大的痛苦)。 ViewModel 的生命周期与activity何时结束有关。

LiveDataScope 用于在 LiveData 对象的范围内发出值。这意味着只要 LiveData 对象还活着并且有订阅者,协程就会工作,但是一旦所有订阅者都退出协程就会停止。一旦 LiveData 再次激活,此协程也会重新启动。

基本上有 2 个协程上下文,每个协程上下文负责其元素的生命周期。

PS:

It sounds like ViewModelScope takes care of lifecycle automatically and you can do network request in the block.

首先,网络请求不能从主线程完成,你通常在IO范围内完成,你可以阅读more here. The second thing is that you should take a look at the lifecycle of the ViewModel compared to Activity if you want to understand why LiveDataScope is usually combined with ViewModelScope, you can read about that here

对您的问题的简短回答是,您不能确定视图是从 ViewModelScope 创建的,因此如果您想将某些更新推送到 UI,您应该推送它们,只要有人订阅了 LiveData,这就是 LiveDataScope 发挥作用的地方。

注意:如果OP的作者已经对此有所了解,那么这可能是该主题的迟到答案,但提供了一些指示@IgorGanapolsky 的参考评论。


让我们看看viewModelScope & LiveDataScope

之间的主要区别是什么

1。视图模型范围:

Official doc says that, CoroutineScope tied to this ViewModel. This scope will be canceled when ViewModel will be cleared, i.e ViewModel.onCleared is called

意味着 协程作用域与 ViewModel 绑定,一旦 ViewModel 被清除,这个作用域就会通过取消所有子协程作业来销毁。

基本上,在 MVVM 模式中,我们使用 ViewModel 绑定到特定的 Activity/Fragment。因此,一旦 Activity/Fragment 被销毁,它的 ViewModel 就会达到清除状态。因此,它会取消由 viewModelScope 开始的所有未完成作业 ,抛出 CancellationException.

因此 viewModelScope 用例是:在 ViewModel 中,当你有任何要调用的挂起函数并需要 CoroutineScope,尽管制作了新的,但您可以直接使用 viewodel-ktx 库中开箱即用的这个。

class SomeViewModel: ViewModel() {

    fun someFunction() {
        viewModelScope.launch {
            callingSomeSuspendedFun()
            callingAnotherSuspendedFun()
        }
    }
}

请注意,您不需要显式重写 ViewModelonCleared() 方法来取消作用域,它会自动为您完成,干杯!

2。 LiveDataScope:

现在说到LiveDataScope,其实是为了更好地支持LiveData/CoroutineLiveData而提供的接口,可以开箱即用CoroutineScope!使用 livedata-ktx 版本

现在想象一下您有一个 MVVM 模式并且想要 return LiveData 从存储库到视图模型的情况。您的存储库还包含一些挂起的函数和一些协程范围。

在那种情况下,当您执行一些暂停的方法调用并且 return 结果作为实时数据时,会有一些额外的工作。获得结果后,您需要将数据转换为特定的实时数据。请参阅下面的示例:

class SomeRepository {

    suspended fun someApiCall() : LiveData<Result> {
        val result = MutableLiveData<Result>()
        someCoroutineScope.launch {
            val someData = someOtherCallToGetResult()
            result.postValue(someData) 
        }
        return result
    }
}

想象一下,由于 LiveData 没有对协程的任何支持,您不得不编写上面的代码块...但直到现在!

现在您可以直接使用 liveData { } 函数 return 您的 LiveData 对象给您 LiveDataScope 的范围,这样您就可以继续暂停的工作并在同一级别发出结果,而不是像上面那样弄得一团糟。所以上面的代码块现在可以通过以下代码或更好的代码进行优化:

class SomeRepository {

    suspended fun someApiCall() : LiveData<Result> {
        return liveData<Result> {
            val someData = someOtherCallToGetResult()
            emit(someData)
        }
    }
}

因此,如果您将 LiveData 从存储库公开到视图模型而不是在内部创建新的视图模型,那么在使用 MVVM 模式时,liveData 的用例将处于存储库级别。请注意,没有关于 liveData 方法不应该直接在视图模型中使用的经验法则。如果你想完全避免viewModelScope,你可以。


TL;DR

查看liveData方法,

Doc states that, The liveData building block serves as a structured concurrency primitive between coroutines and LiveData. The code block starts executing when LiveData becomes active and is automatically canceled after a configurable timeout when the LiveData becomes inactive. If it is canceled before completion, it is restarted if the LiveData becomes active again. If it completed successfully in a previous run, it doesn't restart. Note that it is restarted only if canceled automatically. If the block is canceled for any other reason (e.g. throwing a CancelationException), it is not restarted.

我希望这是有道理的!