The following is the first few sections of a chapter from Android's Architecture Components, plus headings for the remaining major sections, to give you an idea about the content of the chapter.
Services have been an oft-overused bit of the Android SDK. Still, a foreground service is a key part of many apps, providing ongoing functionality to the user even though the app’s UI is gone. For example, most audio player apps (music, audiobooks, etc.) rely on foreground services to play that audio.
One way to communicate with a service is to bind to it, using
This is a very flexible option, as you can define your own API that the service
exposes and clients consume. However, binding to services can be tricky, particularly
when configuration changes come into the picture.
And any time that configuration changes become a problem,
should be a place to turn to come up with a solution.
So, in this chapter, we will explore how you can wrap your bound service in a Architecture Components-based API.
Binding to a service sounds easy: call
bindService() on a
ServiceConnection object. That
ServiceConnection object is called with
onServiceConnected() once the binding is ready, and you are passed an
object that you can use to get at the API exposed by the service. Later, you can call
unbindService(), passing in the same
ServiceConnection, to drop the connection
to the service.
However, there are three problems:
Contextobjects for binding and unbinding
ServiceConnectionobject is state — we need to hold onto that to be able to unbind
startService()on it), unbinding from the service immediately destroys it… even if you might bind again milliseconds later
This makes it tricky to bind from an activity, as configuration changes run right into all three of those problems.
The classic solution involved using the
Application singleton for binding
and a retained fragment for holding onto the
ServiceConnection across configuation
changes. While the
Application singleton is still a good idea, nowadays we
can replace the retained fragment with a
Another wrinkle comes with getting data from the service. We can pull such data
by calling methods on its API. Or, the service could push data… somehow. For
example, we could supply a callback object via the API, which the service can
use to provide data updates. However, once again, this callback is part of our
state, so we need to think about how we can manage it with our
addition, we have threading to consider, particularly if our service is in
a separate process from our UI. This is a place where
LiveData can shine.
The preview of this section was traded for a bag of magic beans.