m-azam
January 16, 2019, 8:49am
1
suspendCoroutine is a low-level primitive that is designed for conversion of callbacks into suspending functions. You should not use suspendCoroutine in your high-level code, precisely because invocation of suspendCoroutine exposes coroutine implementation details (a Continuation object) and can break the illusion of sequential execution in the way you’ve shown.
In particular, you should not mix your business-logic with suspendCoroutine invocations. Your high-level code should never work with C…
in this post it is said that suspend coroutines are low level primitives that are to be used to convert call backs into suspending functions.
> suspend fun < T: Any > Call < T > .exec(): CallResult < T > = suspendCoroutine {
enqueue(object: Callback < T > {
override fun onFailure(call: Call < T > ? , error : Throwable ? ) {
Log.e(tag(), error ? .message)
it.resume(ApiResponseFailure(error ? .let {
return @let it
}.run {
return @run Throwable(Constants.GENERIC_ERROR_MESSAGE)
}))
}
override fun onResponse(call: Call < T > ? , response : Response < T > ? ) {
if (response ? .isSuccessful == true) {
response.body() ? .run {
it.resume(ApiResponseSuccess(this))
}
} else {
response ? .errorBody() ?
.run {
it.resume(ApiResponseFailure(HttpException(response)))
}
}
}
})
}
In the code above I am using suspend coroutine to get results from callbacks onFailure and onResponse from retrofit. Is this a correct use case for suspend coroutines? If not can you tell me how to replace the suspendCoroutine used here?
1 Like
fvasco
January 16, 2019, 10:30am
2
Yes, it is.
However you have to resume always or you coroutine suspends indefinitely.
Consider the following code:
suspend fun <T> Call<T>.executeAwait(): Response<T> = suspendCancellableCoroutine { continuation ->
check(!isExecuted())
continuation.invokeOnCancellation { this@executeAwait.cancel() }
enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>, error: Throwable) {
continuation.resumeWithException(error)
}
override fun onResponse(call: Call<T>, response: Response<T>) {
continuation.resume(response)
}
})
}
4 Likes