Using ViewModel and LiveData in your Android App

A common trap

Since the dawn of Android, application development has been a bit like the wild west. As developers, we want to build fast so sometimes we neglect the architectural design of our applications from the start. A designer hands off the UI and we go over the requirements for our project and start building. The MainActivity starts out lean but we create a bunch of objects for our business logic, hook into framework API’s to start services or leverage hardware from the device resulting in a 2K line file and error-prone code. But we can do much better by taking some extra time to think about separation of concerns within our application. The applications we are building should be modular, extensible and testable. So how do we accomplish this in GUI applications?

Loaded answer: developing an architecture for the application!

Popular GUI architectures:

All these patterns encompass similar concepts. The main idea is we have a Model that contains our business logic, which will be mostly Android agnostic so we can test the code we are writing without the framework dependencies. We have a View that is responsible for displaying information to the user and handling interactions from the user with the on-screen widgets. Finally, we have the ViewModel which is responsible for the display logic for our model (business logic) into the view. But what does that actually mean?

Things may become clearer with the following diagram:

The View is responsible for loading the layout, attaching listeners to UI elements as well as hooking into Android Framework APIs such as system services, custom service implementations, broadcast receivers, etc. Depending on the design choices the view will also be responsible for injecting dependencies or creating the dependencies for the other components in the design.

The ViewModel is responsible for facilitating communication between the view and the data access layer containing application state and business logic.

The Model will handle everything else related to the business decisions of the application including remote connections to REST APIs, data persistence for offline scenarios, and anything else that could be a business rule for the application.

Hopefully, this clears things up for now but if not don’t worry we are going to work through an example.

App Scenario

Let’s think about how we can accomplish the following task: Build an app that lets me search for places using a textual phrase using Google’s Places API. Cool project, I know! But how do we design this in a robust way?

Architecture Components!

In GUI applications there are plenty of design patterns to improve the design of our applications such as MVP, MVC, MVVM, as well as a few others. It has not always been easy to decide which to use when and there is certainly no silver bullet. It has become a common idiom though to use however, we have seen best practices emerge over time in building great apps from developers among the community and open source projects from companies across the world. It was only recently that Google took a stab at actually providing some built-in APIs on Android to help guide the architectural structure of our applications via Architecture Components but wow are they useful.

For our purposes, we are going to look into three components from the new libraries but only one will be the main area of focus.

  1. LifecycleOwner
    • Since the latest release of the support library, we now have activities and fragments implementing the LifecycleOwner interface. So we won’t have to worry about this too much for now but it is important to know it is needed for the ViewModel.
  2. LiveData/MutableLiveData
    • LiveData and MutableLiveData are generic data holder classes that can be observed within a life cycle. Remember LifecycleOwner? These objects allow the data they hold to be observed when changes are made. The distinction between the two, however, is that MutableLiveData exposes the setValue(T) and postValue(T) methods. This means we can change the underlying value and the UI will reflect those changes automatically if we attach an observer in which we update the view. There is also a way to attach an observer without a LifecycleOwner which you can read more about here┬ábut we won’t focus on that here.
  3. ViewModel (main area of focus)
    • ViewModel is a class that is responsible for preparing and managing data for an Activity or Fragment. It is where a developer can hook into the business logic and the best part is data outlives the life cycle of the Fragment or Activity it is used within. This means objects are not recreated everytime the screen rotates or your app is backgrounded(unless of course, the system kills your app to free up resources).

Architecture

So we have thought a little bit about the architecture of our app and we will implement the following:

  • Search screen to get user input through a form field
  • Search result screen to display the results
  • Detail screen to display more information about a search result
  • A repository which will make HTTPS request to the Google Places API using Retrofit
  • Business logic class (ViewModel) which will use the repository to get data and manage it

All source code is written in Kotlin and available on Github.

Let’s skip over the easy parts since we already know how to collect input from an EditText and pass it as an extra through a Bundle to a Fragment.

The Search Results Screen layout xml:

The important parts of the layout really are the Toolbar and the RecyclerView everything else is meant to improve the UI/UX.

Place List Fragment:

Note: important information is in the comments above. If you looked through this code you will notice using the MainViewModel we were able to request the places using the query from the extras and search the places API. We also attached a listener which allows us to update the UI when the request finishes.

Place Detail Fragment

If the comments weren’t enough the important thing to note here is since we are attaching the MainViewModel to the hosting activity of these two fragments we viewed the source of above we only need to re-attach to it and our data is still there. This means we can navigate to and from the same place from the list or list of places and the data will persist.

And finally, the MainViewModel

In the MainViewModel we have all our business logic nicely separated from the rest of our application. The MutableLiveData holder class around our PlacesResponse and PlacesDetailsResponse allow us to observe the changes applied to them when the rest call finishes.

Summary

As you can see LiveData and ViewModel are very powerful components that can help build better apps. Hopefully, this shows how powerful the LiveData and ViewModel classes are and convinces you to at least look into using them to help architect your application. In an upcoming tutorial, I will show you how we can test this code easily.

Please leave a comment or share if you enjoyed the tutorial.