https://kotlinlang.org logo
#orbit-mvi
Title
# orbit-mvi
m

miqbaldc

04/22/2021, 9:06 AM
thanks for the exception handler features guys ❤️ https://github.com/orbit-mvi/orbit-mvi/blob/main/samples/orbit-calculator/src/main[…]lin/org/orbitmvi/orbit/sample/calculator/CalculatorViewModel.kt is it possible to idiomaticly make the exception catch as a flow?
Copy code
val state = MutableStateFlow(...)

state.map {
  // a reducer
}.catch {
  // catch the exception happened in a reducer
}
suggestion:
Copy code
reduce { 
   // omitted
}.catch {
   when (exception) {
     // to distinguish between stateA & stateB exception, unless it's a general toast
     ExceptionFromStateA -> state.copy(a = // do something with data specific to stateA)
     ExceptionFromStateB -> state.copy(b = // similar to the above apprach)
   }

   // or a general error message
   state.copy(errorMessage = it.message)
}
m

Mikolaj Leszczynski

04/22/2021, 9:55 AM
Hey — thanks for the suggestion. I’ll get back to you tomorrow
@miqbaldc Hey, thanks for the suggestion. What would be the benefit versus a simple
try/catch
block or Kotlin’s
runCatching()
? E.g. this works out of the box:
Copy code
reduce {
                runCatching {
                    // This returns a state or throws an exception
                }.getOrElse {
                    // This gets called if it catches an exception
                    state.copy(id = 0)
                }
            }
The reason I’m asking is that exceptions thrown in reducers will likely be dependent on your implementation - from experience I gained on a project leaning heavily on MVI I don’t really remember a real case where a reduction would throw exceptions. In fact - why throw an exception if you can provide a fallback state inline? Otherwise you’re splitting your reducer up into two blocks, which is not great for readability. The sample you’re pointing to is pretty synthetic, we should probably run the op before the reduction happens. Historically, we stepped away from a stream-like syntax on purpose to keep Orbit’s syntax clean and simple, close to vanilla coroutines. Our previous experience with RxJava based MVI wasn’t great. TL;DR I’m not sure we need this, unless you can convince me otherwise. cc @appmattus thoughts?
2
m

miqbaldc

04/23/2021, 12:46 PM
Ah, nice insight didn't realize that
runCatching
exist. Our current usecase to using
.catch
operator was inspired from: pedroql/MVFlow & Ezike/Baking-App
will update the github link, still AFK 🙏
m

Mikolaj Leszczynski

04/23/2021, 12:54 PM
I used to work with Pedro! His library was inspired by Orbit 1 AFAIK 😉
we have bit of a different philosophy with orbit 2
❤️ 1
m

miqbaldc

04/23/2021, 1:00 PM
I'm agreed with you regarding the reducer doesn't need to throw an exception. In the Baking App from daniel also exist in the action processor instead. In this case, Orbit-MVI processor was
intent { }
cmiiw @Mikolaj Leszczynski
The actual usecase was when calling repository and throws the error
m

Mikolaj Leszczynski

04/23/2021, 1:07 PM
Yep - the stream catch is perfectly fine in a stream-based approach but doesn’t really fit Orbit 2. The right thing to do here is to wrap the repo call.
m

miqbaldc

04/26/2021, 1:11 AM
does it something like this? cmiiw
Copy code
fun loadDataForId(id: Int) = intent {
   postSideEffect(MySideEffect.Toast("Loading..."))
   
   val result = try {
       repository.loadData(id)
   } catch (e: NetworkException) {
       postSideEffect(MySideEffect.Toast(e.code().humanizedMessage()))
       null
   }

   reduce {
       state.copy(data = result)
   }
}

private fun Int.humanizedMessage() = when (this) {
   404 -> "Ooops, There's no such resources exist"
   400 -> "Ooops, we can't process those data"
   // ... any other http error code here
   else -> "OOops, something went wrong"
}
m

Mikolaj Leszczynski

04/26/2021, 6:43 AM
yes, something like that will work
m

miqbaldc

04/26/2021, 6:49 AM
nice, with orbit-mvi our MVI solutions is simplified now ❤️ thanks a lot guys K
🙇 1
🎉 2
4 Views