Bound Services on Android

updated Jan. 15, 2019
Card image cap

Table of Contents:


Prefer video over reading? watch the video


Introduction


With respect to Services on Android, you have two categories:

  1. Started Services
  2. and Bound Services

This article is focused on bound services.


What is a Bound Service?


I think the best way to think of a bound service is to compare it with a server. When you start a service with the intention to bind something to it, you essentially have the intention to start a server, and bind to it with some kind of client. At it's core, you're defining a client-server interaction. The service acts as the server, and an activity acts as the client.

That probably sounds a little confusing so let me explain a little better.

I think the naming of "bound services" is a little misleading. Because it's not technically bound to anything. Other things bind to it. The things that bind to it are known as clients. Some examples of clients can be activities or other Android applications attempting to communicate with your service.


Keep in mind that this blog post will be focusing on cases when the client is in the same application (AKA the same linux process) as the service. Therefore Inter-process communication (IPC) is not an issue. If I was including examples where other applications were attempting to communicate with the bound service, then we'd need to include some form of IPC facilitation. For some light reading see this reference on AIDL :).


What Advantages Are Gained with a Bound Service?


Now that you have a better if of what a bound service is, I'm sure you're dying to know why you should use one.

Personally, I like to use bound services when I know there's going to be consistent/frequent communication between an activity and the service.

For example, suppose I wanted to start a Bluetooth connection with some device and retrieve data readings from this device every 5 seconds. For the sake of practicality let's say it's a GPS module that my phone can connect to via bluetooth. When I send certain commands to this device I can retrieve information about it's location in the world.

Using a bound service here would be ideal. The service would be responsible for connecting to the external GPS module and maintaining an open connection where data can flow freely. After the connection is made, the service would be acting as a server. At that point I would bind an activity to the service. The activity is then acting as a client.

  1. Once the activity is bound, I can very easily send commands to the service (from the client aka the activity)
  2. The commands would be received by the service and transmitted to the external GPS module
  3. The external GPS module would respond by sending the relevant information to the service
  4. And the service would then broadcast the retrieved information back to the activity



How to Implement a Bound Service


Enough of all this theory, let's get practical and do an example.

In the example below I'm going to create a service class that has the ability to generate a random number. The service will have a public "getter" method for generating and then returning a random number to a client that asks for it. An activity will act as a client.

Step 1: Building the Service Class

  1. First of all, notice that the class is extended by Service. All services, whether they're bound services or started services, must be extended by the Service class.
  2. Next, notice the MyBinder class. The MyBinder class is used for the client Binder. The Binder object is responsible for returning an instance of MyService to the client.
  3. At the top of the file you can see an object of type MyBinder is declared. That's what's going to be returned to the client.
  4. The onBind method is how the client is able to get the MyBinder object. When the client binds to the service, the onBind method is fired and returns the MyBinder reference.
  5. And of course the getRandomNumber method is responsible for generating a random number. Once the client (activity) is bound to the service, it will have access to all the public methods in the service class. In this case there's just one.




Step 2: Declaring the Service in the Manifest

As per the Android docs, "All services must be represented by elements in the manifest file. Any that are not declared there will not be seen by the system and will never be run.".



Step 3: Starting the Service

*** This is important ***

When it comes to bound services, there's technically two ways you can start the service.

  1. The good ol' fashion way, by calling startService and passing an intent
  2. Or the backdoor way: A Service will automatically start when a client binds to it. So if the services isn't running and something binds to it, it will start up automatically.
But there's a catch. If a service is started when a client binds to it, it will also stop when all clients are unbound. That means if a client binds to a service that was not running, the service will start, but as soon as all clients unbind from the service, the service will be destroyed.

But if you start a service using startService and then bind to it, the service will continue running even when the client is unbound. So depending on your situation you might want to do one or the other.

Here's an example of starting a service using startService. I'm not going to show an example of starting a service by binding to it yet, since we'll be looking at an example of how to bind a client to a service below.

Note that this is the simplest way to start a service possible. This service will NOT run indefinitely on Android version 26 and above. To learn how to start a service that will run indefinitely see the section below named: "Running a Service Indefinitely in the Background".




Step 4: Binding the Client to The Service

This is the part I'm sure you've all been waiting for. Binding to the service. This requires quite a bit more code, see the snippet below. I'll walk you through it.

If you want to read my walk-through while you look at the code, open the code in a separate window and put them side by side. Otherwise you won't be able to read and look at the code at the same time.

  1. The binding process is started off by calling the bindService() method. Notice that bindService() is called after the service has started. That's very important if you want the service to continue running even when the client has disconnected. See explanation above.

  2. The mService variable. This is the instance of the MyService class that will exist in the activity. This is essentially the client-server connection.

  3. Next take a look at the ServiceConnection object. This is the object we can use to detect when the client (activity) has successfully bound to the service, and when it has disconnected from the service.

  4. Inside the onServiceConnected method is where the IBinder is returned to the activity. We can use the IBinder object to access an instance of the service. You can see that in action with the line:
    MyService.MyBinder binder = (MyService.MyBinder) iBinder;

    You can then get a reference to the MyService instance by calling
    mService = binder.getService();

    At that point we're good to go. We can use the mService object to access the public methods in the MyService class.

  5. Notice the getRandomNumberFromService() method being called right after the mService object is set. That method is defined at the bottom of MainActivity and returns a random number from the service.



That's all there is to binding an activity to a service. Once it's bound, you can access any of the public methods inside the service at any time. This facilitates a very convenient way to communicate with a service.


Running a Service Indefinitely in the Background


In the examples above, I showed the simplest way possible to start a service. You just create an intent, and call the startService method. Pretty simple.
Intent serviceIntent = new Intent(this, MyService.class); startService(serviceIntent);

On Android versions 25 and below (Nougat and below), a service started this way will run indefinitely. Or at least until the stopSelf() method is called inside the service class. But on Android versions 26 and above (Oreo and above), the service will be destroyed as soon as the activity that started it is destroyed. This makes for a very fragile service.

So what can we do?

For Android versions 26 and above, this is how you need to start a service if you want it to run indefinitely. In the OnCreate method of the service, write something like this:



That's it. That will allow services to run indefinitely on devices running API level 26 and above (Oreo and above).


How to Stop a Foreground Service


If you design a service to run indefinitely, it won't stop even if the application task is removed (Swiped up or removed from the applications recently used list). If you want your service to run indefinitely in the background, that's the point. You want it to be very difficult to stop the service from doing it's thing, whether that's maintaining a bluetooth connection, streaming music, etc..

It turns out, this is kind of a double-edged sword. How do we stop this beast of a service?. For example: suppose you built a service using the methods that I outlined above. The purpose of this service is to stream music. If you started playing an audio file, then "swiped up" to remove the application task, the audio would continue playing.

I encourage you to try this for yourself. I found it extremely creepy. The feeling you get when you essentially "hard-close" an app, but the audio keeps playing, is not one I can describe with text. It's guaranteed to leave you thinking: "I wonder who's listening to me when I don't think anyone's listening."

There's a few ways you can deal with this. The easiest way is to set the stopWithTask attribute to True in the service declaration in the Manifest. It would look like this:
<service android:name=".MyService"
    android:stopWithTask="true">
</service>

Then if the task is removed (ie: closed by swiping up on the recently opened apps list), the service will stop regardless of if anything is bound to it. The stopWithTask attribute is essentially a hard-close. Pretty handy.


Review


Services are confusing. And they've become even more confusing since the changes implemented in Android O. Before I end this article I want to clarify the relative start and stop priorities of bound services.
  1. If a service is started by the literal act of a client binding to it, that service will stop as soon as all clients are unbound. Note that it will only stop once all clients are unbound.

    So if 5 clients bind to the service, then 5 clients unbind from the service, the service will be destroyed.

  2. If a service is started using either the startService method or the startForegroundService method, then a client binds to it, the service will continue running until the stopSelf method is called. The act of unbinding has no effect on whether the service stays alive or not, since it was started before any clients were bound.


Final Thoughts


As I said in the review section, services are confusing. And they seem to become more confusing as time goes on. Staying educated is becoming increasingly difficult when it comes to the Android SDK. Moving forward I hope this article was helpful and you're able to implement bound services in your projects.


Staying in the Loop


If you want to stay in the loop and get an email when I write new blog posts, Follow me on Instagram or join the CodingWithMitch community on my website. It only takes about 30 seconds to register.



Create an Account

Have an account? Log In

CodingWithMitch Members

Unlimited access to all courses and videos

Step by step guides to build real projects

Video downloads for offline viewing

Members can vote on what kind of content they want to see

Access to a private chat with other communnity members & Mitch

A chance to win 1 hour of free consulting every month

Become a Member

CodingWithMitch Members

Unlimited access to all courses and videos

Step by step guides to build real projects

Video downloads for offline viewing

Members can vote on what kind of content they want to see

Access to a private chat with other communnity members & Mitch

A chance to win 1 hour of free consulting every month

Become a Member

Comments