When building Android apps using Kotlin and the MVVM architecture, a common issue developers encounter is that the ViewModel does not update the UI as expected. This article will walk you through the causes and solutions for this problem. We’ll also provide complete working code examples using Android Studio to help you debug and fix it effectively.

Common Reasons Why ViewModel Doesn’t Update UI
- LiveData not observed properly
- Observers bound to the wrong lifecycle
- UI components not refreshed
- Wrong usage of MutableLiveData
- State updates not triggered
Example Case: LiveData Doesn’t Update UI
Let’s build a simple counter app using ViewModel and LiveData. We’ll demonstrate the issue and how to solve it.
1. ViewModel Class (Kotlin)
// CounterViewModel.kt package com.example.viewmodelissue import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class CounterViewModel : ViewModel() { private val _counter = MutableLiveData<Int>().apply { value = 0 } val counter: LiveData<Int> = _counter fun incrementCounter() { _counter.value = (_counter.value ?: 0) + 1 } }
2. Activity Code (Incorrect Usage Example)
// MainActivity.kt package com.example.viewmodelissue import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.viewModels import com.example.viewmodelissue.databinding.ActivityMainBinding class MainActivity : ComponentActivity() { private lateinit var binding: ActivityMainBinding private val viewModel: CounterViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // Wrong: This doesn’t observe lifecycle properly viewModel.counter.observe(this) { binding.counterText.text = it.toString() } binding.incrementButton.setOnClickListener { viewModel.incrementCounter() } } }
Fix: Observe With LifecycleOwner
Make sure you observe LiveData with the correct LifecycleOwner
:
// Correct usage inside onCreate viewModel.counter.observe(this@MainActivity) { count -> binding.counterText.text = count.toString() }
Additional Tips:
- Always use
observe(viewLifecycleOwner)
if you’re using fragments. - Avoid creating multiple observers unnecessarily.
- Use
StateFlow
for better lifecycle-aware reactive streams in complex apps.
Recommended Resource
For deeper understanding on ViewModel and LiveData best practices, refer to the official documentation on Android Developer Guide to LiveData.