Other LiveData Examples
Let’s take a look at a few more examples of using LiveData
, to explore other facets of how this can be used.
Event Bus
LocalBroadcastManager
implements an in-process event bus, where events are delivered to you on the main application thread, and where “events” are Intent
objects.
You can accomplish the same thing, with greater flexibility, by means of a LiveData
object, as can be seen in the General/LiveBus
sample project.
This sample app is derived from one shown in The Busy Coder’s Guide to Android Development, where we have AlarmManager
triggering a service. In principle, that service should do some work, which we are skipping here because we are lazy. However, the fake work is something that the user might care about, and so we want to let the UI layer know about the event if we happen to be in the foreground. Otherwise, we want to raise a Notification
. In The Busy Coder’s Guide to Android Development, implementations of this sample are available for a few event buses, including LocalBroadcastManager
and greenrobot’s EventBus.
Here, though, we will use a MutableLiveData
singleton:
static final MutableLiveData<Intent> BUS=new MutableLiveData<>();
MutableLiveData
is a subclass of LiveData
, with one key feature: it offers a postValue()
method that works like setValue()
but can be called from a background thread. Here, our events are in the form of Intent
objects, the way they would be for LocalBroadcastManager
. However, you could create your own custom event objects if you prefer, and typically that would be a better idea. In this case, the sample is demonstrating a quick-and-dirty change from LocalBroadcastManager
, so we are keeping the event objects the same to reduce the number of code changes.
The service, as part of its work, asks the BUS
whether there are any active observers, by means of hasActiveObservers()
. If hasActiveObservers()
returns true
, we use postValue()
to post the event onto our BUS
. Otherwise, we raise a Notification
, as our UI is not in the foreground.
Our EventLogFragment
registers an observer lambda on the BUS
, adding the events to its ArrayAdapter
:
ScheduledService.BUS.observe(this, intent -> adapter.add(intent));
Unlike LocalBroadcastManager
, this approach performs no Intent
filtering, and we can have as many MutableLiveData
objects as needed. So, you can create custom buses for different event channels, instead of using action strings as you might with LocalBroadcastManager
.
Room
Having DAO methods in Room return a LiveData
is simply a matter of setting them up that way:
@Query("SELECT * FROM Customer WHERE postalCode IN (:postalCodes) LIMIT :max")
LiveData<List<Customer>> findByPostalCodes(int max, String... postalCodes);
Now, findByPostalCodes()
will return a LiveData
. Moreover, it will do so immediately when called, with the actual query being performed on a Room-supplied background thread. You can arrange to register an observer to find out when the results are ready. And, by using the same LiveData
instance after a configuration change, you can get the last-loaded results without having to perform another round of disk I/O.
However, Room has an additional feature: if you make changes to the database through your DAO, Room will deliver fresh results to any registered observer of your LiveData
. So, for example:
- You register an observer on a
LiveData
, returned by a Room@Query
, that represents a list of your entities - Shortly thereafter, you get the list of entities as they exist in the database at present, for you to fill into your
RecyclerView
(or whatever) - Later on, as part of processing a request from the user, you invoke an
@Insert
method on your DAO to add a new entity to the database - Your registered observer gets the updated list of entities as they exist in the database, for you to fill into your
RecyclerView
(or whatever) - And so on
In effect, Room attempts to give you ContentObserver
capabilities, for your own database, tied directly into the LiveData
system.
Note, though, that these changes are tied in large part to your use of the DAO. For example, if you want to insert 100 entities, you could:
- Call a single
@Insert
method that takes aList
of those entities, in which case you will get a single update from theLiveData
- Call a one-entity
@Insert
method 100 times, in which case you will get 100 updates from theLiveData
Doing things in batch form generally will be more efficient, both from a disk I/O standpoint and a LiveData
-updating standpoint. On the other hand, this means that a LiveData
update might represent several changes, and that may require additional smarts to handle properly in terms of updating the UI (e.g., use DiffUtil
to efficiently update a RecyclerView
).
We will see using LiveData
with Room in the next chapter.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.