Wassim Beltaief

ViewModel and LiveData in practice

Thursday, March 22, 2018

For years, Android had no official answer to "how do you survive rotation". You use onSaveInstanceState for small data, a retained Fragment for larger objects, static references if you are not careful about leaks. Everyone has a different solution.

At I/O 2017 Google announces Architecture Components. ViewModel and LiveData. Now there is an official way.

ViewModel

A ViewModel survives configuration changes. When the Activity rotates, Android destroys and recreates it. The ViewModel stays.

class UserViewModel : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user

    fun loadUser(id: String) {
        // this runs in the ViewModel, survives rotation
        repository.getUser(id) { user ->
            _user.postValue(user)
        }
    }
}

In the Activity:

val viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
viewModel.loadUser(userId)

After rotation, ViewModelProvider returns the same ViewModel instance. The network call is not repeated. The data is already there.

LiveData

LiveData is an observable that is lifecycle-aware. It only delivers updates when the observer (Activity or Fragment) is in an active state. If the Activity is in the background, updates are queued until it comes back.

viewModel.user.observe(this) { user ->
    nameTextView.text = user.name
    emailTextView.text = user.email
}

No need to unsubscribe. When the Activity is destroyed, the observer is automatically removed. No memory leak.

Before LiveData, you had to manually unsubscribe from RxJava streams or callbacks in onDestroy. Easy to forget, causes crashes.

The MutableLiveData pattern

Inside the ViewModel, you use MutableLiveData to post updates. Outside, you expose it as LiveData so only the ViewModel can change the value.

// inside ViewModel
private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean> = _loading

fun fetchData() {
    _loading.value = true
    // do work
    _loading.value = false
}

The underscore prefix for the mutable version is a convention that almost everyone follows.

What changes in the codebase

We start moving all the state and logic out of Activities into ViewModels. Activities become thinner. They observe LiveData and update the UI. Business logic lives in the ViewModel.

Combined with a Repository pattern, the architecture becomes clean:

Activity/Fragment -> ViewModel -> Repository -> API/Database

This is not new. MVP had a similar idea. But now it is official, it handles rotation for you, and it integrates with LiveData natively.

The one thing I miss

ViewModel does not survive process death. If Android kills the process and the user comes back, the ViewModel is recreated. You still need onSaveInstanceState for critical state like search query or scroll position.

This is a real limitation. The combination of ViewModel for configuration changes and onSaveInstanceState for process death is correct but adds complexity. Something to be aware of.

Still, Architecture Components are a big improvement. The codebase becomes more predictable.