跪拜 Guibai
← All articles
Android · Android Jetpack · Kotlin

MVI Predates Redux, and Most Android Implementations Get It Right

By 稀有猿诉 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

The debate over what counts as MVI has created unnecessary churn in Android architecture discussions. Knowing that the single-state, sealed-intent pattern matches the original 2014 definition lets teams adopt it without second-guessing whether they are doing MVVM wrong or mislabeling Redux.

Summary

MVI was introduced in 2014 through Cycle.js as a reactive rethinking of MVC, not as a derivative of Redux or Elm. Its creator, André Staltz, took Flux's unidirectional data flow, stripped out the dispatcher and imperative stores, and modeled everything—user intents, state transitions, UI rendering—as pure observable streams. The pattern's mathematical core is `view(model(intent()))`.

The common Android implementation—a single immutable state data class, a sealed interface for user intents, and a reducer function inside a ViewModel—matches the original MVI specification. Claims that this is just MVVM with extra steps misunderstand both patterns: MVVM exposes multiple mutable LiveData streams and lacks a formal reducer, while MVI enforces a single state object and a strict intent-to-state-to-view cycle.

A global store, however, is a Redux concept. An MVI implementation that introduces one ceases to be MVI. The historical record shows MVI and Redux independently drew from Flux; MVI simply arrived first.

Takeaways
MVI was first named and defined by André Staltz in 2014, predating Redux by several months.
The pattern emerged from a reactive reimagining of MVC, not from Redux or Elm's MVU.
MVI's core is a strict cycle: Intent → Model → State → View, expressed as `view(model(intent()))`.
A single immutable state object, sealed intents, and a reducer function inside a ViewModel are sufficient to call an implementation MVI.
MVVM differs fundamentally: it uses multiple mutable LiveData streams and has no formal reducer concept.
Introducing a global store makes an implementation Redux-like, not MVI.
Both MVI and Redux were independently influenced by Flux's unidirectional data flow.
Conclusions

The 'MVI Police' criticism that Kotlin MVI is just MVVM with a state class collapses under historical scrutiny—MVVM never prescribed a single state object or a reducer, and those additions change the architecture enough to warrant a distinct name.

Staltz's original MVI was simpler than Redux by design: no dispatcher, no global store, just observables wired in a cycle. The Android community's instinct to keep MVI lightweight and ViewModel-scoped aligns with that original intent better than Redux-style global state management ever would.

The persistence of the MVI-vs-Redux confusion reveals how easily a later, more popular project can overwrite the perceived lineage of an earlier one, even among experienced engineers.

Concepts & terms
Model-View-Intent (MVI)
A reactive UI architecture pattern that enforces a single immutable state object, models user actions as intent streams, and applies a pure reducer function to produce new states in a unidirectional cycle.
Reducer
A pure function with the signature (PreviousState, Intent) → NewState. It is the sole mechanism for state mutation in MVI and Redux, ensuring state transitions are predictable and traceable.
Flux
An application architecture introduced by Facebook in 2014 that enforces unidirectional data flow through Actions, a Dispatcher, Stores, and Views. It influenced both Redux and MVI independently.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗