Let’s begin with a quick glance from the docs for LiveData
LiveData 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.
So why should you use it?
- It ensures the UI always remains in sync with the data
- It automatically cleans up after itself based on the lifecycle object used. So no callbacks lying around after your Activity or Fragment is finished.
- No more checking for active activity/fragment from the callbacks.
The most basic LiveData
subclasses that you can use straight away are MutableLiveData
to publish your own data based on certain events from the app/framework you are using and MediatorLiveData
to compute live data based off from other LiveData
instances. While both of these deserve a tutorial of their own, I will leave them off for another post since they are already pretty thoroughly covered over the internet.
Let’s jump on how to create a custom Live Data instance. Here we will try to create a HistoricalLiveData
instance that hooks on to another LiveData and stores a history of n
values from that data. Any bells ringing on how this could be useful for you?
Here’s the full implementation
class HistoricalLiveData<T> constructor(source: LiveData<T>, private val maxLength: Int = 10) :
MediatorLiveData<List<T>>() {
init {
this.addSource(source) {
val values = (this.value ?: emptyList()) + listOf<T>(it)
this.postValue(values.subList(listOf(0, values.size - maxLength).max() ?: 0, values.size))
}
}
}
That’s it. Isn’t it pretty? I think it’s almost all self-explanatory. But let’s take a look anyway. We inherit from the MediatorLiveData
class which handles listening for the source LiveData
coming in as an argument very easy in the init
. On the addSource
callback, we add the value to our value
and MediatorLiveData
will take care of everything from there on.
Time to use it now.
private val historicalLocation = HistoricalLiveData<Location>(throttledLocation, 2)
...
historicalLocation.observe(lifecycleOwner, Observer {
Timber.d("Previous 2 locations: %s", it.joinToString(","))
})