我阅读了很多有关Kotlin协程的文档,但仍然有一些疑问。我正在使用带有协程的Retrofit,因此我需要对Dispatchers.IO上下文进行请求,但在Dispatchers.Main上下文中使用result将其分配给ViewModel。我的代码是:
fun doHttpreq() {
viewModelScope.launch(Dispatchers.IO) {
try {
//should I call await() here? (I guess the correct way to keep execution of request outside of Main thread)
val request = RestClient.instance.getItems().await()
withContext(Dispatchers.Main) {
//or should I call await() here? (BUT need request to be executed outside of Main thread!)
if (request.isSuccessful) {
//asign items to ViewModel
} else {
//asign error to ViewModel
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
//asign error to ViewModel
}
}
}
}
答案 0 :(得分:1)
您可以将递延的工作变成变量,然后在您的主调度员上等待它,如下所示:
try {
//Rather than await here, you take your Job as Deffered
val request: Deferred? = RestClient.instance.getItems()
withContext(Dispatchers.Main) {
//Yes, you can await here because it's non-blocking call and can be safely obtained from here once completed
val result = request?.await()
if (request.isSuccessful) {
//asign items to ViewModel
} else {
//asign error to ViewModel
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
//asign error to ViewModel
}
}
关于
await()
的官方文档是什么:
等待该值完成而不会阻塞线程,并在延迟计算完成后恢复,返回结果值或引发相应的异常如果延期取消了。
该暂停功能是可以取消的。如果在等待此挂起功能的过程中当前协程的作业被取消或完成,则此功能将立即以CancellationException继续运行。
此函数可用于通过onAwait子句进行选择调用。使用isCompleted无需等待即可检查此递延值的完成。
答案 1 :(得分:1)
由于协程正在挂起而不是阻塞,因此无需管理它们所运行的线程。在您的情况下,改良会为您处理此问题。此外,Deferred
类型实际上是热数据源。这意味着Call
会在您甚至调用await
之前执行。 await
只是等待数据在那里。
因此,您可以直接在Main
调度程序上启动。因此,您只有一个地方可以从这里致电await()
。
viewModelScope.launch(Dispatchers.Main) {
try {
val request = RestClient.instance.getItems().await()
if (request.isSuccessful) {
//asign items to ViewModel
} else {
//asign error to ViewModel
}
} catch (e: Exception) {
//asign error to ViewModel
}
}