MVVM Architecture in Android — Complete Guide with Example
1. What is MVVM Architecture?
MVVM stands for Model–View–ViewModel. It is a modern architectural pattern widely used in Android development. MVVM separates the UI logic from business logic and data handling, enabling **reactive UI updates** and **better testability**.
2. Key Components of MVVM
- Model: Manages data and business logic. It fetches data from APIs, databases, or repositories.
- View: Displays data to the user and observes data changes. It is “dumb” and contains minimal logic.
- ViewModel: Mediates between the Model and View. It exposes observable data (LiveData or StateFlow) and handles UI-related logic without referencing Android UI classes.
3. MVVM Data Flow
- View observes LiveData / StateFlow in ViewModel.
- User interacts with the UI (View), triggering events in ViewModel.
- ViewModel calls the Model / Repository to fetch or update data.
- Model returns data to ViewModel.
- ViewModel updates LiveData / StateFlow.
- View automatically observes the change and updates the UI.
4. Advantages of MVVM
- Separation of concerns — UI and business logic are decoupled.
- Reactive UI updates via LiveData / StateFlow.
- Easy to unit test ViewModel without Android dependencies.
- Improves maintainability and scalability for large projects.
5. Example: Simple Login Feature Using MVVM
📁 Folder Structure
├── model/
│ └── UserModel.kt
├── repository/
│ └── UserRepository.kt
├── viewmodel/
│ └── LoginViewModel.kt
├── view/
│ └── LoginActivity.kt
└── activity_login.xml
🧩 Model: UserModel.kt
package com.example.mvvm.model
data class UserModel(val username: String, val password: String) {
fun isValid(): Boolean {
return username.isNotEmpty() && password.length >= 6
}
}
📦 Repository: UserRepository.kt
package com.example.mvvm.repository
import com.example.mvvm.model.UserModel
class UserRepository {
fun login(username: String, password: String): Boolean {
val user = UserModel(username, password)
return user.isValid()
}
}
🧠 ViewModel: LoginViewModel.kt
package com.example.mvvm.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.mvvm.repository.UserRepository
class LoginViewModel : ViewModel() {
private val repository = UserRepository()
private val _loginResult = MutableLiveData()
val loginResult: LiveData get() = _loginResult
fun login(username: String, password: String) {
if (username.isEmpty() || password.isEmpty()) {
_loginResult.value = "Fields cannot be empty"
return
}
val success = repository.login(username, password)
_loginResult.value = if (success) "Login successful!" else "Invalid credentials"
}
}
🎨 View: activity_login.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp">
<EditText
android:id="@+id/etUsername"
android:hint="Username"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/etPassword"
android:hint="Password"
android:inputType="textPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btnLogin"
android:text="Login"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
🎬 Activity: LoginActivity.kt
package com.example.mvvm.view
import android.os.Bundle
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import com.example.mvvm.R
import com.example.mvvm.viewmodel.LoginViewModel
import kotlinx.android.synthetic.main.activity_login.*
class LoginActivity : AppCompatActivity() {
private val viewModel: LoginViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
btnLogin.setOnClickListener {
val username = etUsername.text.toString()
val password = etPassword.text.toString()
viewModel.login(username, password)
}
viewModel.loginResult.observe(this) { result ->
Toast.makeText(this, result, Toast.LENGTH_SHORT).show()
}
}
}
6. MVVM Advantages Over MVP / MVC
- View is completely passive — UI updates reactively via LiveData / StateFlow.
- ViewModel contains no Android framework dependencies — easier unit testing.
- Supports lifecycle awareness out-of-the-box with Jetpack components.
- Better separation of concerns for complex apps.
Conclusion
MVVM is the recommended modern Android architecture pattern. Using ViewModel, LiveData, and Repository enables reactive, testable, and maintainable applications. MVVM is especially powerful for apps that require clean separation between UI, business logic, and data layers, making it highly preferred for large-scale Android projects and CTO-level discussions.