This post series explores the implementation of Android Architecture Components (AAC) so we make the magic go away. In this instalment we’ll focus on LiveData . You can see the other posts here:

What is LiveData?

Photo by Chris Liverani on Unsplash

Let’s look at the definition from Android’s documentation:

L iveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.

In summary:

LiveData follows the Observer pattern, notifying subscribers of new data being available.

follows the Observer pattern, notifying subscribers of new data being available. LiveData is Lifecycle aware, which means that it will notify subscribers only when it’s in an active lifecycle state, and it will dispose the subscription when the Lifecycle terminates and is destroyed.

How does LiveData implement the Observer pattern?

Now that we have a brief introduction to the concept, let’s look at how it implements the Observer pattern.

The following snippet is how LiveData is expected to be consumed, as specified by Android’s documentation:

First, the ViewModel creates a MutableLiveData and exposes it. Then, the Activity will consume it by creating an Observer , and calling .observe(this, nameObserver) .

Diving into observe , we can see how it manages the subscriptions:

The first thing we notice is that observe depends on a LifecycleOwner and the Observer instance we create. When the lifecycle is not in the DESTROYED state, observe creates a LifecycleBoundObserver instance using the LifecycleOwner and the Observer .

After ensuring we don’t add twice the same Observer with different LifecycleOwner s, it sets the wrapper to listen for Lifecycle events.

Now that we know how subscription works, let’s look at how the notification of observers is executed:

Setting the value is rather straight forward. LiveData will assert we are on the main thread, update mData to hold the latest data, and notify the observers.

In dispatchingValue we can see that it will invalidate a previous dispatch if needed, and iterate the observers using considerNotify where:

It checks that the lifecycle is active.

It checks that the version dispatched is newer than the last version received.

Calls onChanged with the data we are setting.

We’ll revisit later how considerNotify won’t post the event if the Lifecycle is not active, and as a note; postValue is able to dispatch new data from any thread in a safe manner, but this is outside of the scope of this article.

How doesLiveData become Lifecycle aware?

As we disovered from the first post of this series, the ViewModel will be reused while the Activity is destroyed and recreated, and LiveData will continue to work undisturbed by events such as screen rotations and backgrounding the app.

When we looked at how the LiveData is observed, we noticed that a LifecycleBoundObserver is created by wrapping the real observer and the LifecycleOwner .

Disposing the subscription

When the Activity or Fragment is destroyed, the subscription will have to be automatically disposed. Let’s look into how it’s achieved by looking at the LifecycleBoundObserver .

In the implementation we can see:

shouldBeActive actively checks the Lifecycle state of the owner

actively checks the Lifecycle state of the owner onStateChanged will remove this from the observer list when the DESTROYED state is reached. This allows to create the observer in onCreate without having to worry about unsubscribing or disposing of it in any other way in onDestroy .

Finally, how does Activity implement LifecycleOwner and when is it tagged as DESTROYED ?

The first thing we can see is that SupportActivity uses a LifecycleRegistry as the instance of Lifecycle , and that this is passed into the constructor. Our guess is that LifecycleRegistry will be listening to Activity state changes in it, however it seems to be doing so in a somewhat obscure way. We’ll resort to using a breakpoint in onStateChanged to inspect the stack trace of callers:

When the control flow is not clear enough, a breakpoint is your friend.

Browsing the stack trace, we can see that the events are sent from a ReportFragment instance.

The ReportFragment is injected in the Activity in onCreate , and behaves as a headless Fragment :

Delaying notifications on non-active Lifecycle state

Remember how considerNotify didn’t post the events when the Lifecycle is inactive? Let’s look at how we recover the data when the Lifecycle becomes active again.

The key is in LifecycleBoundObserver where onStateChanged calls activeStateChanged , implemented in ObservableWrapper , to re-submit the latest value when it becomes active again:

Summary