LocalBroadcastReceiver for communicating between Services and Activities
As a newcomer to Android, one of the things that’s surprisingly tricky is communicating with a Service (an application component for long-running operations) from other parts of your application. You can’t simply call methods on it – you have to come up with a way to broadcast messages.
Background
On the Services guide, there’s three types of services: Scheduled, Started, and Bound. Scheduled services are for periodic operations, which isn’t relevant to my interests right now.
My use case is this: I want the phone to open a socket and run a TCP server for an indeterminate amount of time. The application should be able to send messages to clients connected to this server. The server shouldn’t go down when the application is minimized. So which type of service do I want?
At first, a bound service seems like it might be what I want because it’s easy to send messages to:
A bound service offers a client-server interface that allows components to interact with the service (good), send requests (good), receive results (good), and even do so across processes with interprocess communication (IPC) (eh). A bound service runs only as long as another application component is bound to it (bad). Multiple components can bind to the service at once (eh), but when all of them unbind, the service is destroyed (bad).
Well, what about the Started type?
After it’s started, a service can run in the background indefinitely (good), even if the component that started it is destroyed (good). Usually, a started service performs a single operation (eh) and does not return a result to the caller (eh). For example, it can download or upload a file over the network. When the operation is complete, the service should stop itself (good).
I’m not sure if starting a long-running server counts as a single operation, but perhaps we could consider it to be.
At this point, I’m thinking that while the interface that a bound service provides sound enticing, overall it has too many undesirable characteristics. So that leaves the Started type. How do we communicate with it?
LocalBroadcastManager
As you probably know, Android has this thing called BroadcastReceiver, which I’ve taken to be basically applications shouting to each other. But we don’t want applications conversing, but rather parts of the same application conversing with other parts. LocalBroadcastManager facilitates exactly this.
Concept
Here’s the concept and procedure we’re going to follow in the next steps. There’s a Service and one or more Activities that want to communicate with the service. The Service and Activities will be decoupled – neither will retain a reference to the other.
- Activity start the Service.
- Service signals to the Activity that it’s ready to go.
- Activity starts sending messages to the Service.
- (Optional) Service sends messages back.
Code
Alright, lets get to the code. The following examples are in Kotlin, but the concept should hopefully be clear enough.
Activity
So with that, we’ve started the Service. Let’s look at the Service implementation now.
Service
So there you have it – a simple Started service and bidirectional communication with an Activity.