Joel Denke
04/26/2024, 4:10 AMcombineFlowResults (
flowA, flowB, flowC, flowD
) { a, b, c, d ->
UiStateOf(a, b, c, d)
}.onStart(Uistate.Loading)ephemient
04/26/2024, 5:35 AMkotlin.Result.ephemient
04/26/2024, 5:41 AMJoel Denke
04/26/2024, 6:56 AMephemient
04/26/2024, 7:17 AMsealed interface Result<out T> {
data class Success<out T>(val value: T) : Result<T>
data class NetworkError(val exception: IOException) : Result<Nothing>
// etc.
modeled after what actually happens in your application, not just some untyped Throwable as kotlin.Result does
- or use Arrow Either or some other alternative which also allows for modeling thatephemient
04/26/2024, 7:18 AMkotlin.Result exists for the sake of some generic infrastructure like Kotlin coroutinesJoel Denke
04/26/2024, 7:20 AMephemient
04/26/2024, 7:20 AMcombine overload will work fineephemient
04/26/2024, 7:21 AMJoel Denke
04/26/2024, 7:21 AMephemient
04/26/2024, 7:21 AMJoel Denke
04/26/2024, 7:21 AMJoel Denke
04/26/2024, 7:22 AMJoel Denke
04/26/2024, 7:24 AMYoussef Shoaib [MOD]
04/26/2024, 8:45 AMzip from Arrow or the result DSL from ArrowJoel Denke
04/26/2024, 10:12 AMYoussef Shoaib [MOD]
04/26/2024, 10:33 AMresult {
UiStateOf(resultA.bind(), resultB.bind(), resultC.bind(), resultD.bind())
} // Type: Result<UiState>Joel Denke
04/26/2024, 11:24 AMYoussef Shoaib [MOD]
04/26/2024, 11:25 AMJoel Denke
04/26/2024, 6:15 PMsuspend fun fetchCombinedData(): UIState {
return try {
val deferredResult1 = async { NetworkRepository1.fetchData1() }
val deferredResult2 = async { NetworkRepository2.fetchData2() }
val deferredResult3 = async { NetworkRepository3.fetchData3() }
val result1 = deferredResult1.await()
val result2 = deferredResult2.await()
val result3 = deferredResult3.await()
UIState.Success(listOf(result1, result2, result3))
} catch (e: Exception) {
UIState.Error("Error: ${e.message}")
}
}
Each async here I added to illustrate my Flow. Usually return Flow from each async here and not often combine all at once. Open for change mental model of something better. I usually have suspend at api layer and Flow in repository layer.
And in my case in Compose want combine these results into one ui state data class, with loading, success and error state. Aggregate all at once.Youssef Shoaib [MOD]
04/26/2024, 7:24 PMFlow<Result<Blah>>, I'll represent them here with asyncs:
suspend fun fetchCombinedData(): UIState = result {
val deferred1 = async { ... }
val deferred2 = async { ... }
val deferred3 = async { ... }
UIState.Success(listOf(deferred1.await().bind(), deferred2.await().bind(), deferred3.await().bind()))
}.getOrElse { UIState.Error("Error: ${e.message}") }Youssef Shoaib [MOD]
04/26/2024, 7:27 PMflowA.combine(flowB, flowC, flowD) { a, b, c, d ->
result {
UiStateOf(a.bind(), b.bind(), c.bind(), d.bind())
}.getOrElse { UiState.Error(e.message) }
}Joel Denke
04/26/2024, 7:27 PMJoel Denke
04/26/2024, 7:28 PMYoussef Shoaib [MOD]
04/26/2024, 7:28 PMresult builder also does try-catch and collects any exceptions, but it also allows calling .bind() on Result valuesYoussef Shoaib [MOD]
04/26/2024, 7:28 PMJoel Denke
04/26/2024, 7:30 PMJoel Denke
04/26/2024, 7:31 PMJoel Denke
04/26/2024, 7:33 PMYoussef Shoaib [MOD]
04/26/2024, 7:33 PMDataLayerError, you can have handling for those errors without having to make them exceptionsYoussef Shoaib [MOD]
04/26/2024, 7:35 PMcollect or combine your flows, call your suspend funs normally, and await your asyncs, and then call bind() on any of them that might have a domain error.Joel Denke
04/26/2024, 7:37 PMJoel Denke
04/26/2024, 7:38 PMYoussef Shoaib [MOD]
04/26/2024, 7:39 PMRaise<E> allows you to throw an error of type E, so you simply would have to take in multiple Raise values for every instance you have. I'd suggest checking the Arrow docs btw, they go into good detail with examplesJoel Denke
04/26/2024, 7:41 PMJoel Denke
04/26/2024, 7:42 PMJoel Denke
04/27/2024, 6:57 AMYoussef Shoaib [MOD]
04/27/2024, 12:16 PM