这是 ViewModel 中 Coroutines IO 调度程序的正确用法吗?
Is this a proper usage of Coroutines IO dispatcher in ViewModel?
我想确定以下是否正确使用了 IO 调度程序:
- 在 ViewModel 中,我从存储库中调用方法,而存储库从 api 中调用方法(Retrofit 用作网络库)。我读到对于任何网络方法我都可以使用 IO 调度程序但是通过阅读许多示例我没有找到任何调用 IO 调度程序的示例。
我用一下合适吗?
这是没有调度程序的代码
private suspend fun getNews() = viewModelScope.launch {
_newsResponse.postValue(Resource.loading(null))
try {
repository.getNews().let {
if (it.isSuccessful){
_newsResponse.postValue(Resource.success(it.body()))
}else{
_newsResponse.postValue(Resource.error(it.errorBody().toString(), null))
}
}
}
这是使用 IO Dispatcher 的代码
private suspend fun getNews() = viewModelScope.launch {
withContext(Dispatcher.IO){
_newsResponse.postValue(Resource.loading(null))
try {
repository.getNews().let {
if (it.isSuccessful){
_newsResponse.postValue(Resource.success(it.body()))
}else{
_newsResponse.postValue(Resource.error(it.errorBody().toString(), null))
}
}
}
}
- 正确的做法是什么(有或没有 IO 调度程序?
- withContext(Dispatcher.IO) 和我做 viewmodelscope.launch(IO) 时一样吗?
- 这取决于您想 运行 您的工作的调度员。如果您想在
IO
或 Main
作为 viewModelScope
. 默认调度程序的调度程序上执行此操作
viewModelScope.launch(IO)
在 IO
调度器上启动一个新协程,其中 withContext(Dispatcher.IO)
仅将当前协程调度器从当前切换到 IO
。
如果 repository.getNews()
是一个适当组合的挂起函数,则根本不需要指定调度程序。一个正确组合的挂起函数不会阻塞,它会挂起,因此在不指定调度程序的情况下从任何上下文调用都是安全的。一个不正确组合的挂起函数将是一个内部调用阻塞函数而没有在内部指定可以处理其阻塞调用类型的调度程序的函数。
Retrofit 提供了用于发出请求的挂起函数,因此您应该能够以适当的方式轻松编写 repository.getNews()
。
您也不需要使用 liveData.postValue()
,因为默认情况下视图模型范围位于主调度程序上。您可以使用标准值 setter 属性.
关于你的第二个问题,这两种方法在这种特定情况下是等效的,因为你将协程的全部内容包装在 withContext
块中。但就像我说的,你根本不需要指定调度程序,所以你应该使用一个简单的 launch
调用。
我想确定以下是否正确使用了 IO 调度程序:
- 在 ViewModel 中,我从存储库中调用方法,而存储库从 api 中调用方法(Retrofit 用作网络库)。我读到对于任何网络方法我都可以使用 IO 调度程序但是通过阅读许多示例我没有找到任何调用 IO 调度程序的示例。
我用一下合适吗?
这是没有调度程序的代码
private suspend fun getNews() = viewModelScope.launch {
_newsResponse.postValue(Resource.loading(null))
try {
repository.getNews().let {
if (it.isSuccessful){
_newsResponse.postValue(Resource.success(it.body()))
}else{
_newsResponse.postValue(Resource.error(it.errorBody().toString(), null))
}
}
}
这是使用 IO Dispatcher 的代码
private suspend fun getNews() = viewModelScope.launch {
withContext(Dispatcher.IO){
_newsResponse.postValue(Resource.loading(null))
try {
repository.getNews().let {
if (it.isSuccessful){
_newsResponse.postValue(Resource.success(it.body()))
}else{
_newsResponse.postValue(Resource.error(it.errorBody().toString(), null))
}
}
}
}
- 正确的做法是什么(有或没有 IO 调度程序?
- withContext(Dispatcher.IO) 和我做 viewmodelscope.launch(IO) 时一样吗?
- 这取决于您想 运行 您的工作的调度员。如果您想在
IO
或Main
作为viewModelScope
. 默认调度程序的调度程序上执行此操作
viewModelScope.launch(IO)
在IO
调度器上启动一个新协程,其中withContext(Dispatcher.IO)
仅将当前协程调度器从当前切换到IO
。
如果 repository.getNews()
是一个适当组合的挂起函数,则根本不需要指定调度程序。一个正确组合的挂起函数不会阻塞,它会挂起,因此在不指定调度程序的情况下从任何上下文调用都是安全的。一个不正确组合的挂起函数将是一个内部调用阻塞函数而没有在内部指定可以处理其阻塞调用类型的调度程序的函数。
Retrofit 提供了用于发出请求的挂起函数,因此您应该能够以适当的方式轻松编写 repository.getNews()
。
您也不需要使用 liveData.postValue()
,因为默认情况下视图模型范围位于主调度程序上。您可以使用标准值 setter 属性.
关于你的第二个问题,这两种方法在这种特定情况下是等效的,因为你将协程的全部内容包装在 withContext
块中。但就像我说的,你根本不需要指定调度程序,所以你应该使用一个简单的 launch
调用。