I am trying to figure out what is the best way to handle the upload of a lot of data ( up to 1000s of files/images, around 500kb each) with retrofit2 and kotlin.
I have tried to use coroutines withContext() method, but when using enqueue, it just iterates through my entire list of files enqueuing them all at once, which sometimes leads to problems that some of the files are not uploaded correctly.
If i use retrofits execute(), the file upload is handled synchronous, which is also a pain and very slow to execute, but definetly far more reliable, since in testing it managed to upload all files every time.
How could I manage to get the best of both worlds, to run this asynchronous with multiple files uploading at once, but not as slow as the synchronous method?
My current implementation was something like this, please also mind that I am still a beginner in Kotlin and do not leverage all of the functional programming advantages for working with lists yet:
for(item in list) { ...
launch {
withContext(Dispatchers.Main) {
restAPIService.enqueue(object : RetryCallback<JsonObject>() {
override fun onResponse(
call: Call<JsonObject>,
response: Response<JsonObject>) {
if (response.isSuccessful) {
// handle response etc.
------------- EDIT -------------
After the response and hint how to use the .flatMap(), I have now implemented something like this and it seems to be working:
myList
.asFlow()
.flatMapMerge(5) { frame ->
flow<Pair<Frame, Response<JsonObject>>> {
//init parameters to pass to the retrofit 2 call
val restAPIService = RestAPIService.RetrofitApi.retrofitService.uploadImages(
"Bearer $accessToken",
projectPart,
filePart,
folderNamePart,
metaDataPart
)
retrofitSuspendCall(restAPIService, frame, recording)
}
}
}
private suspend fun retrofitSuspendCall(
request: Call<JsonObject>, frame: Frame, recording: RecordingWithFrames): Response<JsonObject> = suspendCoroutine { continuation ->
request.enqueue(object : Callback<JsonObject> {
override fun onResponse(call: Call<JsonObject>, response: Response<JsonObject>) {
if (response.isSuccessful) {
continuation.resume(response)
}
//also handling onfailure
})