Gabor Varadi
2 min readMay 5, 2018

--

Hmm I guess the trick here is that it is possible to create the functional loop with:

.scan(StatisticsViewState.idle(), reducer)
.distinctUntilChanged()
.replay(1)
.autoConnect(0)

Also, Redux on its own defined the Reducer as (State, Action) -> State. In this MVI variant, you have a few mappings prior: Intent -> Action, then Processor does Action -> Result, and only then do you actually evaluate the new state with the reducer (based on the result of the task executed by the action processor): (State, Result) -> State.

So, MVI addresses certain pain points of initial Redux proposition (which, as you can see, would NOT be able to support asynchronous operations nor one-off events — and why MVI added some extra elements in the loop for that).

One could argue that the Processor is a middleware that accesses things only before, but not after evaluation of new state.

They do have some tricks up their sleeves though: one-off actions are portrayed as two results:

.flatMap { tasks ->
// Emit two events to allow the UI notification to be hidden
// after some delay
pairWithDelay(
TasksResult.ActivateTaskResult.Success(tasks),
TasksResult.ActivateTaskResult.HideUiNotification)
}

In the end, all the real magic happens in the ProcessorHolders, and from Rx perspective, it uses ObservableTransformer just like as specified in Jake Wharton’s Managing State with RxJava. A bit boilerplate-y, but theoretically sound.

As long as you can read Rx, there definitely is value in MVI ~ explicit state machine that handles threading / async ops. If you can test Rx transformers, you can test your logic.

Overall, if this example separated State from Data, and instead of always starting the stream with StatisticsViewState.idle(), they persisted the State into Bundle in onSaveInstanceState() and restored that as initial value for the reducer across process death, then this example would be complete.

--

--

Gabor Varadi

Android dev. Zhuinden, or EpicPandaForce @ SO. Extension function fan #Kotlin, dislikes multiple Activities/Fragment backstack.