Как загружать много файлов асинхронно с Kotlin сопрограммами и дооснащением2 - PullRequest
2 голосов
/ 27 января 2020

Я пытаюсь выяснить, как лучше всего обрабатывать загрузку большого количества данных (до 1000 файлов / изображений, около 500 КБ каждое) с помощью retrofit2 и kotlin.

I Я пытался использовать сопрограммы с методомContext (), но при использовании enqueue он просто перебирает весь мой список файлов, ставя их в очередь сразу, что иногда приводит к проблемам, связанным с неправильной загрузкой некоторых файлов.

Если я использую модификацию execute (), загрузка файла обрабатывается синхронно, что также является трудной задачей и очень медленным в выполнении, но, безусловно, гораздо более надежным, поскольку при тестировании ему удавалось загружать все файлы каждый раз.

Как мне удалось получить лучшее из обоих миров, запустить этот асинхронный процесс с одновременной загрузкой нескольких файлов, но не так медленно, как синхронный метод?

Моя текущая реализация была примерно такой, пожалуйста, не забывайте что я все еще новичок в Kotlin и не использую все преимущества функционального программирования для работы Король со списками еще:

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.

------------- РЕДАКТИРОВАТЬ -------------

После ответа и подсказка, как использовать .flatMap (), я теперь реализовал что-то вроде этого, и, кажется, работает:

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