Where is suspendCoroutine supposed to be used?


#1


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?


#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)
        }
    })
}

#3

Thank you.