Reputation: 7515
I read a lot of docs about Kotlin coroutines but still having some doubts. I'm using Retrofit with coroutines so I need to do request with Dispatchers.IO context but use result within Dispatchers.Main context to assign it to ViewModel. My code is:
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
}
}
}
}
Upvotes: 2
Views: 401
Reputation: 39853
As Coroutines are suspending instead of blocking, there should not be any need to manage the thread they are running on. In your case Retrofit handles this for you. Also the Deferred
type is actually a hot data source. This means that the Call
is executed before you even call await
on it. await
just waits for the data to be there.
So instead you can launch on the Main
dispatcher directly. Therefore you only have one place to call await()
from.
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
}
}
Upvotes: 1
Reputation: 12118
You can take your deffered job in variable and then await it on your Main dispatcher like below :
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
}
}
What official doc states about
await()
:
Awaits for completion of this value without blocking a thread and resumes when deferred computation is complete, returning the resulting value or throwing the corresponding exception if the deferred was cancelled.
This suspending function is cancellable. If the Job of the current coroutine is cancelled or completed while this suspending function is waiting, this function immediately resumes with CancellationException.
This function can be used in select invocation with onAwait clause. Use isCompleted to check for completion of this deferred value without waiting.
Upvotes: 1