Android中的LiveDataScope与ViewModelScope

时间:2019-08-28 19:29:08

标签: android android-livedata kotlin-coroutines android-viewmodel

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

2 个答案:

答案 0 :(得分:4)

注意:如果 OP的作者已经对此有所了解,那么这可能是该主题的较晚答案,但为@IgorGanapolsky的引用注释提供了一些指针。 / p>


让我们看看viewModelScopeLiveDataScope之间的主要区别是什么

1。 viewModelScope:

官方文档说,CoroutineScope与此ViewModel相关。这个 清除ViewModel时,范围将被取消,即 ViewModel.onCleared被称为

这意味着协程范围与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()
        }
    }
}

请注意,您无需显式覆盖onCleared()的{​​{1}}方法即可取消范围,它会自动为您加油!

2。 LiveDataScope:

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

现在设想一种情况,您正在使用MVVM模式,并且想要从存储库返回CoroutineScope来查看模型。您的存储库还包含一些暂停的功能和一些协程范围。

在这种情况下,当您执行一些挂起的方法调用并将结果作为实时数据返回时,将需要做一些额外的工作。得到结果后,您需要将数据转换为特定的实时数据。参见下面的示例:

LiveData

想象一下,由于class SomeRepository { suspended fun someApiCall() : LiveData<Result> { val result = MutableLiveData<Result>() someCoroutineScope.launch { val someData = someOtherCallToGetResult() result.postValue(someData) } return result } } 对协程没有任何支持,您不得不编写以上代码块... 但是直到现在!

现在,您可以直接使用LiveData函数,该函数将返回liveData { }对象,从而为您提供LiveData的作用域,使您可以继续进行暂停的工作并同时发出结果水平,而不是像上面那样混乱。因此,上面的代码块现在可以通过以下代码或更好的代码进行优化:

LiveDataScope

因此,如果您从存储库向视图模型公开LiveData而不是创建新的内部viewmodel,则在使用MVVM模式时liveData的用例将处于存储库级别。请注意,没有class SomeRepository { suspended fun someApiCall() : LiveData<Result> { return liveData<Result> { val someData = someOtherCallToGetResult() emit(someData) } } } 方法的经验法则不应直接在viewmodel中使用。如果您想完全避免使用liveData,则可以。


TL; DR

签出liveData方法,

Doc指出,viewModelScope构建块用作 协程和liveData之间的结构化并发原语。当LiveData变为 活动,并在可配置的超时后自动取消 LiveData无效。如果在完成前被取消, 如果LiveData重新变为活动状态,它将重新启动。如果它 在上一次运行中成功完成,它不会重新启动。注意 仅在自动取消后才重新启动。如果块是 由于其他任何原因而被取消(例如,抛出 LiveData,它不会重新启动。

我希望这有道理!

答案 1 :(得分:0)

名称暗示它们的实际含义:

  

为应用程序中的每个ViewModel定义了一个ViewModelScope。任何   如果在此范围内启动的协程会自动取消   ViewModel已清除。

这意味着您可以在ViewModel范围内的协程中执行某些任务(例如连续处理)。优点是您不再需要在何时停止ViewModel来停止协程(这在处理诸如Java线程之类的全局事务时会很痛苦)。 ViewModel的生命周期与结束活动的时间有关。

LiveDataScope用于发出LiveData对象范围内的值。这意味着只要LiveData对象处于活动状态,并且有一些协程将正常工作的订户,但是一旦所有订户退出,协程将停止。一旦LiveData再次处于活动状态,此协程也会重新启动。

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

PS:

  

听起来好像ViewModelScope自动照顾了生命周期   您可以在该区块中进行网络请求。

首先,无法从Main线程完成网络请求,通常是在IO范围内进行,您可以阅读more here。第二件事是,如果您想了解LiveDataScope通常与ViewModelScope结合的原因,那么应该查看一下ViewModel与Activity相比的生命周期,您可以了解有关here的信息。 。

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