Table of Contents
Overview of MVVM in Android
Model View ViewModel, usually shortened to MVVM, is an architectural pattern that helps you separate concerns in your Android apps. In MVVM, you split your code into three main parts. The View is the user interface layer, such as Activity, Fragment, and XML layouts. The ViewModel is a middle layer that holds UI data and handles user actions in a lifecycle aware way. The Model represents your data and business logic, such as repositories, database access, and network calls.
The core idea of MVVM on Android is that the View observes data from the ViewModel, usually with LiveData or similar observable types. The ViewModel exposes data and operations as a clean API, and the View reacts to changes without containing logic that does not belong to the user interface. This structure reduces coupling between the UI and the data layer and makes your code easier to test and maintain.
In MVVM, the View never directly modifies the Model. It only sends user events to the ViewModel. The ViewModel updates the Model and then exposes new state that the View observes.
Roles of Model, View, and ViewModel
The Model in MVVM covers anything related to your app data and rules that are not specific to the Android UI. This includes network calls with Retrofit, Room database operations, repositories that coordinate multiple data sources, and pure Kotlin classes that implement your app logic. The Model should not hold references to Android UI classes such as Activity or Context tied to the UI, except where absolutely required, for example in a database or network client that needs an application context.
The View is everything that draws on the screen and receives user interaction. Typical Views are Activity, Fragment, and custom Views described in XML or code. The View is responsible for showing data, starting navigation, and forwarding user actions such as button clicks or text input to the ViewModel. The View should contain as little decision logic as possible. It should not fetch data directly or perform heavy computation.
The ViewModel acts as a bridge between the View and the Model. It holds UI related data in a lifecycle aware way, uses repositories or other Model classes to load or modify data, and processes user actions from the View. The ViewModel does not know about XML, Activity, or Fragment instances. Instead, it exposes observable properties, such as LiveData, that the View can observe. This makes ViewModels testable without Android frameworks.
Data Flow and Responsibilities
MVVM encourages a clear, one direction data flow. The View sends user events to the ViewModel. Examples of these events include button clicks that trigger loading data, retry actions after an error, and form submissions. The ViewModel receives these events, calls the appropriate Model components, and then updates its exposed data state.
The View observes this state and updates the UI automatically when changes occur. For example, a View might observe a LiveData<List<User>> property from the ViewModel. When the ViewModel sets a new list of users after a repository fetch, the View receives the update and refreshes a RecyclerView. The View does not need to know where the data came from or how it was processed.
A common pattern in MVVM is to expose UI state as a single object that contains all the information the View needs. For example, the ViewModel might expose a LiveData<UiState> where UiState is a data class containing flags like isLoading, errorMessage, and the actual data. The View then renders loading indicators, error messages, and content based on this state. This reduces the risk of inconsistent UI where separate flags get out of sync.
The ViewModel should never hold a reference to an Activity, Fragment, or View instance. Holding such references can cause memory leaks and breaks the separation of concerns that MVVM provides.
MVVM with ViewModel and LiveData
On Android, MVVM becomes practical through the combination of ViewModel and LiveData. The ViewModel class survives configuration changes, such as screen rotations, so it can keep UI data in memory while Activities or Fragments are recreated. LiveData is an observable data holder that is lifecycle aware. It only notifies observers when the associated lifecycle owner, such as an Activity or Fragment, is in an active state.
In a typical MVVM setup, you create a ViewModel class for each screen or feature and extend ViewModel or AndroidViewModel. Inside this class you define LiveData properties that represent the data and state you want to show in the UI. The View obtains an instance of the ViewModel, then calls observe on the LiveData to react to changes.
A simplified example of the ViewModel part might look like this.
class UserListViewModel(
private val repository: UserRepository
) : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> = _users
fun loadUsers() {
// Implementation detail: call repository and set _users value
}
}
In the corresponding View, for example a Fragment, you observe users and update your UI whenever the list changes. Because LiveData is lifecycle aware, it will automatically stop sending updates when the Fragment view is destroyed and resume when it is active again. This reduces boilerplate code that you would otherwise need to manage observer registration and removal.
For events that should be consumed only once, such as navigation commands or showing a message, you need to be careful, because LiveData replays the last value to new observers. Patterns to handle one time events often use special wrappers or shared flows, but these details are beyond the basic introduction and will be explored in more advanced sections.
Example Structure of an MVVM Screen
To understand MVVM as a structure, imagine a simple screen that shows a list of notes and allows the user to add a new note. In MVVM, the View would contain the XML layout that defines the RecyclerView and the add button, and an Activity or Fragment that references these views. The Activity or Fragment obtains the NoteListViewModel instance via a ViewModel provider and sets observers on the exposed LiveData. When the add button is clicked, the View does not create the note itself. Instead, it calls a ViewModel method, such as viewModel.onAddNoteClicked(text).
Inside the ViewModel, the onAddNoteClicked function validates the note text and calls a repository method to save the note to a database. Once the repository returns, the ViewModel updates its LiveData with the new list of notes. The View then receives this updated list and passes it to the RecyclerView adapter to refresh the displayed items.
This separation makes it possible to write tests for NoteListViewModel without any Android framework involvement. You can provide a fake repository, call onAddNoteClicked, and assert that the ViewModel exposes the expected list of notes through its observable properties. At the same time, the View remains a thin layer that is mainly responsible for binding and layout, which is easier to change and redesign without affecting the underlying logic.
MVVM vs Other Architectures
MVVM is one of several architectural options on Android. Older patterns like Model View Controller and Model View Presenter also separate concerns, but they differ in how the layers communicate and where the logic lives. In MVC, Activities were often treated as controllers, which caused them to become too large and complex. In MVP, Presenters handled logic and called methods directly on the View, which meant the View and Presenter had a tighter relationship.
MVVM on Android uses observer based communication, where the ViewModel does not know anything specific about the View implementation. The View subscribes to observable properties and reacts to changes. This reduces coupling compared to MVP, because the ViewModel does not call methods on the View. Instead, it only exposes data and high level events. Combined with Architecture Components like ViewModel and LiveData, MVVM fits naturally into the Android lifecycle and reduces common problems such as lost data on rotation and memory leaks caused by retained references.
Although MVVM is widely recommended in modern Android development, it is not the only choice. In more advanced topics, you will see that other patterns and libraries, such as unidirectional data flow or Jetpack Compose specific approaches, can build on the same principles of clear separation and observable state. For now, MVVM with ViewModel and LiveData provides a solid foundation for structuring your apps.
Common Pitfalls and Best Practices in MVVM
In practice, it is easy to drift away from the architecture if you are not careful about responsibilities. One common mistake is to put network calls or database queries directly into an Activity or Fragment. This violates the MVVM idea, because the View now owns logic that belongs to the Model and ViewModel. Instead, keep heavy work and data management inside the ViewModel and repository classes.
Another pitfall is turning the ViewModel into a large class that knows too much. If your ViewModel starts to handle unrelated features or contains long methods that manage complex data flows, it becomes a so called God object, which is hard to understand and maintain. To avoid this, keep each ViewModel focused on a single screen or feature, and move reusable logic into helper classes or the Model layer.
You should also be careful when using LiveData for navigation or one time events. Because LiveData stores the last value, configuration changes can accidentally repeat actions like showing a dialog or launching a new screen. Solutions often include using wrapper classes that mark events as handled or using other observable types that are designed for streams of events.
Keep the View simple, keep business and data logic in the Model, and keep coordination and UI state in the ViewModel. Violating these boundaries leads to fragile and hard to test code.
Finally, remember that MVVM is a guide, not a rigid rulebook. Use it to make your code clearer and more modular, but adapt patterns when necessary to keep your app simple and understandable. As you add more Architecture Components and libraries, MVVM will serve as the backbone that organizes your screens and data flow.