Understanding Android Architecture: From MVC/MVP/MVVM to MVI
This article reviews classic Android architectural patterns—MVC, MVP, and MVVM—highlights their limitations, introduces the MVI pattern as a more streamlined alternative, and provides a detailed Kotlin implementation with ViewState, ViewEvent, and unidirectional data flow examples.
Introduction
Android development has matured and several architectural patterns such as MVC, MVP, and MVVM are widely used. While MVVM is officially recommended, it still has drawbacks that can be mitigated by the MVI pattern.
Classic Architecture Overview
MVC
MVC separates the view, controller, and model, but on Android the Activity often plays both view and controller roles, violating the single‑responsibility principle and causing tight coupling between view and model.
MVP
MVP introduces a Presenter that handles business logic, allowing the view to interact only with the presenter and reducing coupling. However, the presenter holds a reference to the view and the view interface can become large as the page grows.
MVVM
MVVM replaces the presenter with a ViewModel and uses two‑way data binding so that UI updates automatically when the model changes. Many developers dislike data binding, and MVVM still requires duplicated mutable/immutable LiveData declarations and scattered view‑model interactions.
What Is MVI?
MVI (Model‑View‑Intent) borrows ideas from front‑end frameworks and emphasizes a single source of truth and unidirectional data flow. Its components are:
Model – represents UI state rather than domain data.
View – subscribes to state changes and renders UI.
Intent – user actions wrapped as intents sent to the model.
The data flow proceeds as: Intent → Model updates State → View renders the new State.
Practical MVI Implementation (Kotlin)
Below is a concise Kotlin example that demonstrates the core pieces.
ViewState and ViewEvent
data class MainViewState(val fetchStatus: FetchStatus, val newsList: List
)
sealed class MainViewEvent {
data class ShowSnackbar(val message: String) : MainViewEvent()
data class ShowToast(val message: String) : MainViewEvent()
}ViewState Updates in ViewModel
class MainViewModel : ViewModel() {
private val _viewStates = MutableLiveData
()
val viewStates = _viewStates.asLiveData()
private val _viewEvents = SingleLiveEvent
()
val viewEvents = _viewEvents.asLiveData()
init {
emit(MainViewState(fetchStatus = FetchStatus.NotFetched, newsList = emptyList()))
}
private fun fabClicked() {
count++
emit(MainViewEvent.ShowToast(message = "Fab clicked count $count"))
}
private fun emit(state: MainViewState?) { _viewStates.value = state }
private fun emit(event: MainViewEvent?) { _viewEvents.value = event }
}Observing ViewState in the View
private fun initViewModel() {
viewModel.viewStates.observe(this) { renderViewState(it) }
viewModel.viewEvents.observe(this) { renderViewEvent(it) }
}Dispatching Actions from the View
class MainActivity : AppCompatActivity() {
private fun initView() {
fabStar.setOnClickListener { viewModel.dispatch(MainViewAction.FabClicked) }
}
}
class MainViewModel : ViewModel() {
fun dispatch(action: MainViewAction) = reduce(viewStates.value, action)
private fun reduce(state: MainViewState?, viewAction: MainViewAction) {
when (viewAction) {
is MainViewAction.NewsItemClicked -> newsItemClicked(viewAction.newsItem)
MainViewAction.FabClicked -> fabClicked()
MainViewAction.OnSwipeRefresh -> fetchNews(state)
MainViewAction.FetchNews -> fetchNews(state)
}
}
}This structure centralises state management, reduces boilerplate, and makes the flow of user actions explicit.
Conclusion
MVI offers a clear unidirectional data flow, easier state tracing, and less repetitive code compared with MVVM, especially when data binding is avoided. Its drawbacks include potentially large immutable state objects and increased memory usage due to state copying. Developers should choose the pattern that best fits their project requirements.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.