Android 中的 LiveDataScope 与 ViewModelScope
LiveDataScope vs ViewModelScope in Android
我在这里阅读如何使用协程 https://developer.android.com/topic/libraries/architecture/coroutines。让我感到困惑的是 LiveDataScope
和 ViewModelScope
之间的区别。听起来 ViewModelScope
会自动处理生命周期,您可以在块中进行网络请求。当从服务器接收到数据时,post 的值变为 livedata
。但是当我继续阅读时,还有另一个关于 LiveDataScope
的主题,这对我来说似乎是多余的,因为您已经可以通过使用 ViewModelScope
和 livedata
来实现相同的结果。这两者之间的主要区别是什么?我应该在什么时候选择使用一个而不是另一个?
名副其实:
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()
}
}
}
请注意,您不需要显式重写 ViewModel
的 onCleared()
方法来取消作用域,它会自动为您完成,干杯!
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.
我希望这是有道理的!
我在这里阅读如何使用协程 https://developer.android.com/topic/libraries/architecture/coroutines。让我感到困惑的是 LiveDataScope
和 ViewModelScope
之间的区别。听起来 ViewModelScope
会自动处理生命周期,您可以在块中进行网络请求。当从服务器接收到数据时,post 的值变为 livedata
。但是当我继续阅读时,还有另一个关于 LiveDataScope
的主题,这对我来说似乎是多余的,因为您已经可以通过使用 ViewModelScope
和 livedata
来实现相同的结果。这两者之间的主要区别是什么?我应该在什么时候选择使用一个而不是另一个?
名副其实:
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 thisViewModel
. This scope will be canceled whenViewModel
will be cleared, i.eViewModel.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()
}
}
}
请注意,您不需要显式重写 ViewModel
的 onCleared()
方法来取消作用域,它会自动为您完成,干杯!
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 andLiveData
. The code block starts executing whenLiveData
becomes active and is automatically canceled after a configurable timeout when theLiveData
becomes inactive. If it is canceled before completion, it is restarted if theLiveData
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 aCancelationException
), it is not restarted.
我希望这是有道理的!