When discussing which architecture to adopt in modern Android development, the debate almost always boils down to MVVM vs. MVI.
However, looking at recent trends, it’s clear these two aren’t opposing forces; they are converging.

Google’s Stance: UDF over Specific Pattern Names
If you dive into Google’s official “Guide to App Architecture,” you’ll notice the term “MVI” is rarely mentioned. Instead, Google consistently pushes the concept of UDF (Unidirectional Data Flow).
Why does Google use the abstract term “UDF” instead of “MVI,” which is already familiar to the community?
The reason lies in Google’s preference for flexibility. Their philosophy seems to be:
“Don’t get bogged down by strict naming conventions like MVI. Just ensure the essence of the architecture — one-way data flow — is preserved.”
Whether you use a strict state management library like Redux or implement it with a simple ViewModel, Google’s priority is that you follow the core principle: “State flows down, Events flow up.”
The Modern Standard: Implementing “MVI-flavored MVVM”
In the field, the most common approach to Google’s recommended UDF is what I call “MVI-flavored MVVM” — pouring MVI rules into an MVVM container. This involves three core elements: State, Intent, and Effect.
Here is how it looks in practice:
1. ViewModel Implementation (Managing State and Intent)
// State: Consolidates all UI data into a single object (MVI style)
data class UserListUiState(
val users: List<User> = emptyList(),
val isLoading: Boolean = false
)
// Side Effect: One-time events like navigation or Toasts (MVI style)
sealed class UserListSideEffect {
data class ShowToast(val message: String) : UserListSideEffect()
}
class UserListViewModel : ViewModel() {
// The MVVM "Container"
private val _uiState = MutableStateFlow(UserListUiState())
val uiState = _uiState.asStateFlow()
private val _effect = Channel<UserListSideEffect>()
val effect = _effect.receiveAsFlow()
// Single entry point for all operations (Intent)
fun onIntent(intent: UserListIntent) {
when (intent) {
is UserListIntent.Refresh -> loadUsers()
is UserListIntent.OnUserClick -> { /* ... */ }
}
}
}
2. View Implementation (Jetpack Compose)
@Composable
fun UserListScreen(viewModel: UserListViewModel) {
val state by viewModel.uiState.collectAsStateWithLifecycle()
// Subscribing to Side Effects
LaunchedEffect(Unit) {
viewModel.effect.collect { effect ->
when (effect) {
is UserListSideEffect.ShowToast -> { /* Show Toast */ }
}
}
}
// Sending UI interactions to the ViewModel as Intents
UserListContent(
state = state,
onRefresh = { viewModel.onIntent(UserListIntent.Refresh) }
)
}
Why This Hybrid Approach Wins
In traditional MVVM, UI components often call various functions like viewModel.fetchData() directly. In contrast, introducing an MVI-style Intent creates a single entry point for the ViewModel. This makes logging and debugging — essentially tracking “what is happening in the app right now” — drastically easier.
Furthermore, by centralizing the state into a single UiState data class, you can fully leverage Jetpack Compose’s reactive nature, where the UI automatically recomposes whenever the state changes.
Conclusion: Blurred Lines and the Core Essence
Today, the boundary between MVVM and MVI is fading. Google advocates for “UDF,” and developers respond with what is effectively “MVI.”
This shift signifies that Android development has moved beyond simply piecing components together; it has entered a sophisticated design phase focused on data integrity.
There’s no need to stress over which pattern is “correct.” By using the standard Android MVVM structure while adopting the discipline of MVI’s unidirectional flow, you arrive at what is likely the most robust and sensible choice for 2026.
Thanks for reading!
👏 Clap to support the article
⭐ Follow me for more Android and Jetpack Compose tips
🔔 Turn on email notifications so you never miss a post
The State of Android Architecture: Google’s UDF vs. the Real-World “MVI-flavored MVVM” was originally published in ProAndroidDev on Medium, where people are continuing the conversation by highlighting and responding to this story.




This Post Has 0 Comments