Colin Dodd

Introducing SingleLiveEvent

One of the nice things about LiveData being lifecycle aware is that you don’t need to worry about Views having the latest data from the ViewModel; even after rotate! Sometimes however, that can cause unforeseen issues.

When an Android device is rotated, the View is killed and created again. At that point it is up to the developer to ensure that data is not lost during rotation. If you use LiveData this problem goes away; when the View is recreated it connects to the same LiveData and the previously cached results are returned to the View.

Consider a simple example, where clicking a Button causes an action to happen in the ViewModel. The action can succeed or fail. The View observes a LiveData that broadcasts the success state of the action.

A failure state

In this example, after the action is triggered it fails for some reason. The ViewModel sends out the failure state, and the View which is observing changes receives this failure state. The View decides to handle this failure state by showing a Toast.

So far, so good - there doesn’t seem to be an issue. However, what happens when the device is rotated?

The LiveData rotation bug

🙈

Now every time we rotate the device, the Toast is shown! When the View is recreated, it attaches to the ViewModel, which broadcasts the cached LiveData failure state. As long as we keep rotating the device the toast will keep showing.

SingleLiveEvent to the rescue

In this instance, what we want instead is a LiveData that can only be observed once. No caching, once the value is observed it is gone forever. This is exactly what SingleLiveEvent does. It will only broadcast new values to new subscribers. In practice this means it is useful in situations where you don’t want LiveData such as the example above.

It also handles the situation where there are multiple subscribers. Each subscriber will get the event once. It is only new subscribers that are affected.

SingleLiveEvent is not part of Android Architecture Components, but it is part of the official Architecture Components sample code. Google I/O 2018 is approaching so it will be interesting to see what will happen with the Arch framework.

Colin Dodd

Keeping .observe() out of the ViewModel

If you’ve been using Android Architecture components you’ve probably got a nice separation of concerns. A View, doing everything UI; a Model, keeping control of your data sources; and a ViewModel, shuffling data between the two. LiveData makes it trivial to communicate between these layers, but how do you consume a LiveData in the ViewModel when you don’t have a LifecycleOwner?

One of the big advantages of LiveData is that they are lifecycle aware. When you observe a LiveData you send in a LifecycleOwner and it ensures that the observers are only informed of changes if they are in an active state. It’s great, you can observe and not have to worry about memory leaks, crashes, or stale data.

It’s trivial when observing a ViewModel’s LiveData in the View; but what about the Model to the ViewModel? In my previous article I spoke about how you can use NetworkBoundResource in the Model to return cached database data whilst fetching fresh data from the network. NetworkBoundResource exposes its data through a LiveData which means the ViewModel needs to be able to observe it; but a ViewModel is not a LifecycleOwner nor does it have a reference to a LifecycleOwner. So how can a ViewModel observe these changes?

The wrong solution

There is a method called observeForever - it will allow you to observe without passing a LifecycleOwner but it means the LiveData is no longer lifecycle aware. To stop observing you’ll need to remember to call removeObserver.

I’ve made use of observerForever in tests, but never in production code. I would be interested in hearing under what circumstances observerForever should be used. When it comes to observing in the ViewModel, there is a better solution.

The right solution

The Transformations class is what you need to keep observe out of the ViewModel. With its map and switchMap methods you can consume LiveData from the Model, and transform that LiveData into something which the View can observe.

Say you are developing an email app and you want to show the total number of unread messages. The Model only allows you to get a list of unread emails. The ViewModel however can transform the data from the Model into the unread counter that the View needs.

fun getNumberOfUnreadMessages(): LiveData<Integer> {
   return Transformations.map(model.getUnreadMessages(), { it.size })
}

model.getUnreadMessages is returning a LiveData<List<Email>> which is being mapped to the size of the list. This method returns a LiveData<Integer> which can be consumed by the View. No need to observe in the ViewModel.


switchMap is useful if you need to send a parameter from the View to the ViewModel. Imagine the situation where the user can search through their email with a search query.

fun searchEmail(query: String): LiveData<List<Email>> {
    return model.searchEmail(query)
}

The problem with the above code is that every time the View calls searchEmail a different LiveData will be returned, so the View will need to keep detaching itself and attaching itself to the LiveData returned from this function. By using switchMap we can ensure that the same LiveData is returned and the View doesn’t need to do anything special at all.

private val userInputtedQuery = MutableLiveData<String>()

fun searchEmail(query: String) {
    userInputtedQuery.value = query
}

val searchResult = Transformations.switchMap(userInputtedQuery, { model.searchEmail(it) })

By using switchMap we can observe changes to one LiveData, and trigger the calling of another function. The LiveData is transformed and returned to the View where it can be observed; avoiding having to call observe in the ViewModel.

Conclusion

Make use of the Transformations class to keep observe out of your ViewModel. This keeps your LiveData lifecycle aware and gives you all the benefits that entails.

Colin Dodd

Neat Android Architecture through NetworkBoundResource

One of the joys of working at Bakken & Bæck is that you regularly get the chance to click “New Project” in Android Studio. Last time I got to do that, it was decided that we’d do things using Googles Architecture Components. Rx was out; LiveData was in.

This isn’t going to be a piece comparing the two technologies. Instead I am going to talk about a small utility class NetworkBoundResource and how it can help you architect your apps.

In keeping unopinionated about how to implement architecture, NetworkBoundResource isn’t even a part of the Android framework despite being mentioned in the official guide to app architecture. Instead it exists as part of the samples repo for architecture components.

So, what does it do?

Simply, it allows you to return data from database whilst simultaneously fetching the latest data from the network. When the network call is returned, the result can be stored to database and the new result can be broadcast.

To put that in more concrete terms; say you have an app that fetches the weather for the users current location. The first time the user opens the app there is obviously nothing in the database, so you’ll need to request the latest weather information from the network. Once you’ve fetched the weather information you can show it to the user.

It makes sense to cache that weather information to a database. The next time the user requests the weather information it can then be read from the database. This avoids a network call and works offline.

However, the weather obviously changes so if your user is always seeing the weather thats cached in the database your app isn’t going to be very useful. You’ll want to add some logic that decides how long the information in the database should be considered fresh. Once the information is no longer fresh a new network call can be started to get the latest weather information.

Network calls can fail, or be slow, so ideally you’ll also show the old weather information whilst the network call is happening. When the network call is complete the cached information can be replaced with the latest information and the UI can be refreshed.

All of this logic makes for an app that works offline, feels quick, and is kept up to date. NetworkBoundResource will give you all of this functionality and all it requires is the implementation of 4 methods:

  • loadFromDb is used to return whatever information is stored in the database.
  • shouldFetch decides whether the cached data is fresh or not. If not a new network request will be triggered.
  • createCall creates the network request. NetworkBoundResource will take responsibility for triggering the request.
  • saveCallResult saves the network response into the database. Any mapping of the response into a model object before storing can be done here.

For more concrete implementation details check the section on exposing network status in the official app architecture guide.

Under the hood

NetworkBoundResource works by making use of MediatorLiveData. In essence MediatorLiveData can observe multiple LiveData objects and react to their changes. In this instance there are two LiveData sources; one for the database and one for the network. Both of those LiveData are wrapped into one MediatorLiveData and it is that which is exposed by NetworkBoundResource. More information about MediatorLiveData can be found in the Arch documentation