Как не прерывая Flow вызвать долгую по времени выполнения suspend функцию?

Рейтинг: 1Ответов: 1Опубликовано: 17.04.2023

Я пытаюсь разобраться в принципах работы с Kotlin Coroutines. У меня есть список передаваемый через Flow в Viewmodel.

val chatsFlow = chatsChangedFlow.asSharedFlow()
    .map {
        chatList.map { chat ->
            Chat(
                id = chat.id,
                title = chat.title,
                photo = chat.photo?.let {
                    val photoFilePath = downloadFile(it.file)
                    
                    ProfilePhoto(
                        thumbnail = it.thumbnail.data,
                        filePath = photoFilePath
                    )
                }
            )
        }
    }

И каждый раз при вызове downloadFile Flow дожидается возврата значения, лишь после этого идёт на следующую итерацию.

Можно ли добиться в данном случае поведения чтоб при вызове downloadFile поле filePath оставалось неинициализированным и лишь после обработки значения через некоторое время заполнялось тем самым не прерывая работы Flow?

P.S. downloadFile тоже suspend функция на основе suspendCancellableCoroutine

Ответы

▲ 0
И каждый раз при вызове downloadFile Flow дожидается возврата значения, лишь после этого идёт на следующую итерацию.   

Да и это нормально. Ситуация, когда "скорость обработки значений ниже, чем скорость эмитирования новых данных" корректируется через Стратегии переполнения буфера через метод .buffer()
но что-то подсказывает, что вам это не поможет. вы лишь упустите часть новых данных.

при вызове downloadFile поле filePath оставалось неинициализированным и лишь после обработки значения

для этого в корутинах можно запускать дочерние корутины launch или async
async возвращает тип Deffered - это нейкая работа, результат который вы можете долждаться и получить вызвав на ней .await()

возможно стоить сделать filePath именно типа Deffered<String>, но это не точно.

UPD
отбой =(
внутри .map нельзя вызвать async и из suspend функций нельзя вернуть незаконченные Deferred

UPD 2.0
именно, что из suspend нельзя, но никто не мешает сделать обычный метод, который будет возвращать Deferred!

 fun downloadFile() : Deferred<String> = viewModelScope.async { 
            delay(3000)
            "hello world"
        }