Как я могу использовать результаты двух сопрограмм, возвращающих два разных типа результатов?

#android #kotlin #reactive-programming #kotlin-coroutines #kotlin-flow

Вопрос:

  • Сопрограмма 1 возвращает результат<A>;
  • Сопрограмма 2 возвращает результат<B>;
  • Оба результата должны быть сопоставлены с каким-либо форматом пользовательского интерфейса, например, меню;
  • Если сопрограмма 1 завершится неудачно, процесс должен завершиться и вернуть состояние ошибки пользовательского интерфейса;
  • если сопрограмма 2 завершится неудачно, она также должна завершить процесс и вернуть состояние ошибки пользовательского интерфейса;
  • Сбои сопрограммы обозначаются своего рода пользовательским результатом.Тип сбоя, а не путем создания исключений;
  • И сопрограмма 1, и сопрограмма 2 имеют одинаковую обработку ошибок, но имеют разные требования к отображению для их успешного выполнения.

Я подумывал об использовании потока Котлина, но я все еще разбираюсь в реактивном программировании и хотел знать, будет ли это хорошим вариантом использования. Основное осложнение заключается в том, что случаи сбоя не обозначаются исключениями. Кроме того, я просто не знаю, хороший ли это подход. Пожалуйста, будьте добры!

Что-то вроде следующего:

 sealed class UiState {
   data class menuRetrieved(val menu items: List<MenuItem>) : UiState
   object storageError: UiState
   object unknownError: UiState
}

val uiState = flowOf(coroutine1.await(), coroutine2.await())
    .onEach {
       checkIsError(it) // handle potential error cases
    }
    .transformWhile {
        emit(it)
        it is Result.Success<*> 
    }
    .map { result: Result.Success<*> ->
        result.toMenuItem() // some extension function
    }
    .collect()
 

Обратите внимание, что сопрограммы запрашивают локальное хранилище — например, файлы / общие настройки.

Ответ №1:

Похоже, вы ищете оператора zip из flow

Напр.

 val flowInt = flowOf(1, 2, 3)
val flowString = flowOf("A", "B", "C")
flowInt.zip(flowString) { intValue, stringValue ->
    "$intValue$stringValue"
}.collect {
    Log.d(TAG, it)
}
 

В конечном итоге объедините данные из двух API.
Кредитный блог

Комментарии:

1. Хмм… Не уверен, как это связано с обработкой ошибок.

2. В идеале все ошибки должны быть пойманы таким образом в потоке .catch { flowCollector -> // Handle error with message }.collect { // Handle success } , я видел, что несколько ошибок не пойманы оператором catch {}, поэтому мы также помещаем try catch в блок запуска.