coo*_*ude 4 android kotlin-coroutines
我一直在通过这个Codelab 来了解协程。我仍然不清楚的一件事是,为什么我们需要更改调度程序以确保我们不会阻塞主/UI 线程?如果协程是轻量级线程,那么当我已经在主线程上时,为什么我不能在协程中调用线程阻塞函数(无论它们是否挂起)?
Codelab 解释说(总而言之)如果我编写此代码:
// Repository.kt
suspend fun repoRefreshTitle() {
delay(500)
}
//ViewModel.kt
fun vmRefreshTitle() {
viewModelScope.launch {
_spinner.value = true
repository.repoRefreshTitle()
}
}
Run Code Online (Sandbox Code Playgroud)
...那么这不会阻塞主线程。delay()是一个suspend函数,因此创建的协程viewmodelScope.launch将暂停,直到 500ms 过去。但主线程不会被阻塞。
但是,如果我重构repoRefreshTitle()为以下内容:
suspend fun repoRefreshTitle() {
val result = nonSuspendingNetworkCall()
}
Run Code Online (Sandbox Code Playgroud)
...然后该网络调用实际上将在主线程上完成。那是对的吗?我必须更改为另一个调度程序才能将工作卸载到 IO 线程:
suspend fun repoRefreshTitle() {
withContext(Dispatchers.IO) {
val result = nonSuspendingNetworkCall()
}
}
Run Code Online (Sandbox Code Playgroud)
我一定是把这个问题过于简单化了。我已经处于协程中还不够吗?为什么我必须更换调度员?
Codelab 解释说(总而言之)如果我编写此代码...那么这不会阻塞主线程。delay() 是一个挂起函数,因此 viewmodelScope.launch 创建的协程将暂停,直到 500ms 过去。但主线程不会被阻塞。
正确的。然而,其中真正的“工作”很少,delay()将在主应用程序线程上执行,因为默认的调度程序viewModelScope.launch()是基于Dispatchers.Main.
但是,如果我将 repoRefreshTitle() 重构为以下内容......那么该网络调用实际上将在主线程上完成。那是对的吗?
正确的。nonSuspendingNetworkCall(),例如delay(),将在主应用程序线程上运行。在nonSuspendingNetworkCall(),这不是什么好事。
我必须更改为另一个调度程序才能将工作卸载到 IO 线程
正确的。更具体地说,您需要使用使用后台线程的调度程序。对于I/O,Dispatchers.IO是一个常见的选择。
我已经处于协程中还不够吗?为什么我必须更换调度员?
因为我们不想在主应用程序线程上进行网络 I/O。Dispatchers.Main在主应用程序线程上运行其协程,这是viewModelScope.launch(). 这就是为什么在我写的很多内容中,我专门写的原因之一viewModelScope.launch(Dispatchers.Main)——这更冗长(并且在技术上与默认值略有不同),但对读者来说更明显。
| 归档时间: |
|
| 查看次数: |
4894 次 |
| 最近记录: |