Recently, I applied Coroutines into my project everything seems to be fine but today I meet a problem Upload file/image into server using Coroutine + Retrofit.
It seems that there is no solution for upload file using coroutine + Retrofit, so we must use callback for retrofit.
//Api interface
interface UploadFileApiKotlin {
@Multipart
@POST("/uploadFileApi")
fun uploadFiles(
@Part listUri: List<MultipartBody.Part>
): Call<Response<List<FileResponse>?>>
}
//ViewModel class
serviceScope.launch {
//Insert into db
repository.insertNewExtAct()
//Send data into server.
val call = RequestHelper.getUpLoadFilesKotlinRequest().uploadFiles(partList)
call.enqueue(object : Callback<Response<List<FileResponse>?>> {
override fun onResponse(
call: Call<Response<List<FileResponse>?>>,
response: Response<Response<List<FileResponse>?>>
) {
TODO("Not yet implemented")
}
override fun onFailure(
call: Call<Response<List<FileResponse>?>>,
t: Throwable
) {
TODO("Not yet implemented")
}
})
//Wait for response from server and do logic
}
My question is: How can I suspend coroutines's execution to wait for retrofit's callback ?
You can use suspendCoroutine
or suspendCancellableCoroutine
to work with callbacks (to convert a callback to a suspend
function):
serviceScope.launch {
//Insert into db
repository.insertNewExtAct()
//Send data into server.
uploadFile()
//Wait for response from server and do logic
}
suspend fun uploadFile() = suspendCoroutine<Response<List<FileResponse>?>> { continuation ->
val call = RequestHelper.getUpLoadFilesKotlinRequest().uploadFiles(partList)
call.enqueue(object : Callback<Response<List<FileResponse>?>> {
override fun onResponse(
call: Call<Response<List<FileResponse>?>>,
response: Response<Response<List<FileResponse>?>>
) {
// Resume coroutine with a value provided by the callback
continuation.resumeWith(response.data)
}
override fun onFailure(
call: Call<Response<List<FileResponse>?>>,
t: Throwable
) {
continuation.resumeWithException(t)
}
})
}
suspendCoroutine
suspends coroutine in which it executed until we decide to continue by calling appropriate methods - Continuation.resume...
. suspendCoroutine
mainly used when we have some legacy code with callbacks.
There is also suspendCancellableCoroutine
builder function, it behaves similar to suspendCoroutine
with additional feature - provides an implementation of CancellableContinuation
to the block.