A Primer to ViewModel and LiveData in Android

By Yawei Li & Shaurya Arora

ViewModel and LiveData are classes provided as part of Google’s Android Architecture Components. The ViewModel class is quite simply used to hold the model for the view — UI-related data that outlives Activity/Fragment recreation due to configuration changes (screen rotation, split-screen mode, and window resizing on Chromebooks/foldable devices). The LiveData class, on the other hand, allows for an emitter-observer pattern: elements of the view can subscribe to data in the ViewModel and be notified whenever that data changes. Let’s take a closer look at each of these 2 classes.

ViewModel

The ViewModel class is an integral part of the MVVM (Model-View-ViewModel) architecture pattern that has been endorsed by Google for some time now. A view model (ViewModel object) holds all the data that the view needs along with any associated logic. Usually, this data is exposed as LiveData objects (more on that in the next section).

This is a simple example of a ViewModel object. For some context, this is the view model for a screen that displays a list of NBA teams — this is all dummy data. A loading spinner is used until the teams are ready to be displayed, and an error message is shown in case of any issues loading the data. This view model is obtained in an Activity/Fragment as follows:

Using ViewModelProviders ensures that the same ViewModel object is returned even if the Activity/Fragment is recreated due to a configuration change. Note here that only the view holds references to view models; the view models don’t hold references to the view. This is a key difference between MVVM and MVP (Model-View-Presenter), since in MVP both the view and the presenter hold references to each other.

LiveData

The LiveData class is essentially an observable data holder. Components can subscribe to, or observe, a LiveData object and they will be notified automatically whenever the LiveData’s value changes. Most importantly, LiveData is lifecycle-aware: whenever its value changes, updates are delivered automatically only to those observers that are in an active lifecycle state (“Started” or “Resumed” states). Let’s expand on our TeamViewModel class from above:

For every data point in the view model that we wish to expose, we usually maintain an internal MutableLiveData object. MutableLiveData is a subclass of LiveData that provides a setter method for the underlying value; we cannot set the value on a LiveData instance directly. However, since all logic for setting a LiveData’s value should be encapsulated in the view model, we don’t want to expose this mutability externally. Therefore, we also write a function that exposes the MutableLiveData object only as its super-type (LiveData).

In the above example, isLoadingLiveData is initialized only when a component starts observing it through the isLoading() method. After initialization, the first value assigned to it is true. Here’s how the activity can observe this loading state:

Each time the value of the LiveData object returned by isLoading() — which is really just isLoadingLiveData — updates, the code in the Observer above is executed automatically. The updated value may also be null, so we add a ?.let{} block. In most cases, onCreate() is a good place to start observing a ViewModel’s LiveDatas.

Here’s a noteworthy excerpt from the official Android documentation on LiveData:

Generally, LiveData delivers updates only when data changes, and only to active observers. An exception to this behaviour is that observers also receive an update when they change from an inactive to an active state. Furthermore, if the observer changes from inactive to active a second time, it only receives an update if the value has changed since the last time it became active.

To paraphrase, updates in the value of isLoadingLiveData will be delivered to MainActivity only if MainActivity is in an active state (“Started” or “Resumed”). In addition, MainActivity will receive an update the first time it goes from an inactive (“Paused or “Stopped”) state to an active state. However, subsequent inactive – active transitions in MainActivity’s state will warrant an update from isLoadingLiveData only if the underlying value of isLoadingLiveData has changed since the last time MainActivity was active.

To wrap things up, let’s look at a slightly more complicated example:

UserInformationViewModel exposes a LiveData for a single User, which, as we learn from the loadUserInfo() function, comes from either the database or from the network. Notice that we initialize isLoadingLiveData as true and isErrorLiveData as false so that the observing component (Activity/Fragment) knows to initially show some loading spinner and hide some error view. Moreover, as soon as the first observer subscribes to userLiveData (via getUser()), we initialize userLiveData and call the loadUserInfo() function. Finally, inside loadUserInfo() we set our loading state, error state, and User object as necessary. Ideally, one would use Coroutines or RxJava to wrap database and network operations in worker threads.

And that’s it for a quick primer! Head over to part 2 of this post where we convert a sample project from MVP to MVVM using ViewModel and LiveData.

author

Yawei Li is a Toronto-based Android developer and an avid dog lover.

author

About the author

Shaurya Arora is a Toronto-based Android developer, drummer and prog metal/djent lover.

Join our fast growing team and connect with us on Twitter, LinkedIn,Instagram& Facebook! Learn more about us on our website.

Visit Us on Medium

You might also be interested in…