The MVVM pattern helps organize your app code by separating the user interface from the data and logic. This makes your app easier to build, test, and maintain.
MVVM pattern in Android Kotlin
class MyViewModel : ViewModel() { val data = MutableLiveData<String>() fun updateData(newData: String) { data.value = newData } } // In Activity or Fragment myViewModel.data.observe(this) { updatedData -> textView.text = updatedData }
ViewModel holds and manages UI-related data.
LiveData is used to observe data changes and update the UI automatically.
class MyViewModel : ViewModel() {
val message = MutableLiveData<String>()
fun setMessage(text: String) {
message.value = text
}
}viewModel.message.observe(this) { newMessage ->
textView.text = newMessage
}This app has a button and a text view. When you tap the button, the ViewModel updates the greeting message. The text view automatically shows the new message thanks to LiveData observation.
class MainViewModel : ViewModel() { val greeting = MutableLiveData<String>() fun sayHello() { greeting.value = "Hello, MVVM!" } } class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this).get(MainViewModel::class.java) val textView = findViewById<TextView>(R.id.textView) val button = findViewById<Button>(R.id.button) viewModel.greeting.observe(this) { message -> textView.text = message } button.setOnClickListener { viewModel.sayHello() } } }
Always keep UI code in Activities or Fragments simple and free from data logic.
Use LiveData to automatically update the UI when data changes.
ViewModel survives configuration changes like screen rotations, keeping your data safe.
MVVM separates UI (View), data logic (ViewModel), and data (Model).
ViewModel holds data and exposes it via LiveData for the UI to observe.
This pattern makes apps easier to maintain and test.
Practice
ViewModel in the MVVM pattern?Solution
Step 1: Understand ViewModel responsibility
The ViewModel holds UI data and prepares it for the View, separating UI logic from data sources.Step 2: Differentiate ViewModel from other components
The View handles UI rendering and user input, while the Model manages raw data. ViewModel acts as a bridge.Final Answer:
To hold and manage UI-related data and expose it to the View -> Option DQuick Check:
ViewModel = UI data holder [OK]
- Confusing ViewModel with View
- Thinking ViewModel handles UI rendering
- Assuming ViewModel stores raw database data only
Solution
Step 1: Recall LiveData observe syntax
LiveData.observe requires a LifecycleOwner and an Observer object or lambda with explicit Observer.Step 2: Identify correct Kotlin syntax
viewModel.data.observe(this, Observer { value -> updateUI(value) }) uses the correct method signature with LifecycleOwner and Observer lambda.Final Answer:
viewModel.data.observe(this, Observer { value -> updateUI(value) }) -> Option AQuick Check:
LiveData.observe needs LifecycleOwner + Observer [OK]
- Using observeForever in UI components
- Omitting Observer wrapper in observe call
- Passing lambda without LifecycleOwner
increment() is called twice?class CounterViewModel : ViewModel() {
private val _count = MutableLiveData(0)
val count: LiveData<Int> = _count
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
}Solution
Step 1: Understand initial LiveData value
The MutableLiveData _count starts at 0.Step 2: Trace increment calls
Each increment adds 1 to current value: first call sets 1, second call sets 2.Final Answer:
The count LiveData will have value 2 -> Option AQuick Check:
0 + 1 + 1 = 2 [OK]
- Assuming LiveData does not update value
- Forgetting initial value is 0
- Thinking LiveData is immutable
class UserViewModel : ViewModel() {
val userName = MutableLiveData<String>()
fun updateName(newName: String) {
userName.value = newName
}
fun getName(): String {
return userName.value!!
}
}Solution
Step 1: Analyze getName() method
It returns userName.value!! which forces non-null but value can be null initially.Step 2: Identify risk of NullPointerException
If userName.value is null, !! causes crash. This is unsafe without default or null check.Final Answer:
Forcing non-null with !! on possibly null value -> Option BQuick Check:
!! on nullable LiveData value risks crash [OK]
- Ignoring null safety on LiveData values
- Assuming LiveData always has value
- Confusing MutableLiveData with LiveData usage
1. Repository fetches data asynchronously 2. ViewModel exposes LiveData for user data 3. View observes LiveData and updates UI Which code snippet fits this pattern?
Solution
Step 1: Understand MVVM data flow
Repository handles data fetching, ViewModel holds data and exposes LiveData, View observes LiveData to update UI.Step 2: Match correct separation of concerns
Only ViewModel calls repository fetch, updates MutableLiveData; View observes LiveData to update UI follows this flow: ViewModel updates LiveData, View observes it, no direct UI updates in ViewModel or Repository.Final Answer:
ViewModel calls repository fetch, updates MutableLiveData; View observes LiveData to update UI -> Option CQuick Check:
Repository -> ViewModel -> LiveData -> View [OK]
- Updating UI directly in Repository or ViewModel
- View fetching data directly
- Not using LiveData for UI updates
Ready to prove it?
Pass the test and this pattern moves unknown
