Building an Android service that never stops running

Roberto Huertas
Koa Health
Published in
5 min readJun 29, 2019

I’ve been struggling these days trying to find a way to run an endless service in Android. This is just a guide for all of you who pursue the same goal. Hope it helps!

The problem

Due to Android battery optimizations introduced in Android 8.0 (API level 26), background services have now some important limitations. Essentially, they are killed once the app is in background for a while making them worthless for our purpose of running an always-running service.

According to Android recommendations, we should be using JobScheduler, which seems to work pretty well and will handle wakelocks for us, keeping the phone awake while the jobs are running.

Unfortunately, this won’t work either. JobScheduler will run jobs at Android’s discretion and, on top of that, once the phone enters in Doze Mode, the frequency of these jobs being run will constantly decrease. And even worst, if you ever want to access the network -say you need to send data to your server- you won’t be able to. Check out the list of restrictions Doze Mode imposes.

JobScheduler works well if you don’t mind about not having access to the network and you don’t care about not controlling the periodicity either. In our case, we want our service to run at a very specific frequency and never be stopped, so we’ll need something else.

It’s all about Foreground Services

If you’ve been looking over the internet for a solution to this problem it’s very likely that you’ve eventually arrived to this page from the Android’s documentation.

There, we are introduced to the different types of services that Android provides. Take a look at the Foreground Service description:

A foreground service performs some operation that is noticeable to the user. For example, an audio app would use a foreground service to play an audio track. Foreground services must display a Notification. Foreground services continue running even when the user isn’t interacting with the app.

It seems to be precisely what we’re looking for… an it is, indeed!

Show me the code

Creating a foreground service is really a straight-forward process so I will visit and explain all the steps needed to build a foreground service that never stops.

As usual, I’ve created a repository with all the code in case you want to take a look at it and skip the rest of the post.

Adding some dependencies

I’m using Kotlin for this example, so we will be leveraging coroutines and the Fuel library for HTTP requests.

In order to add these dependencies we must add them to our build.gradle file:

Writing our service

Foreground Services need a notification to be shown so the user is aware that the app is still running. That makes sense if you think about it.

Note that we will have to override some of the Service callback methods that handle key aspects of the service lifecycle.

It’s also very important that we use a partial wakelock so our service never gets affected by Doze Mode. Bear in mind that this will have an impact in the battery life of our phone so we must evaluate whether our use case can be handled by any of the other alternatives Android offers in order to run processes in the background.

There are some utility function calls ( log, setServiceState) and some custom enums ( ServiceState.STARTED) in the code, but don't worry too much. If you want to see where they come from, just take a look at the example repository.

Time to deal with the Android Manifest

We will need some extra permissions for FOREGROUND_SERVICE, INTERNET and WAKE_LOCK. Be sure you don't forget to include them because it won't work otherwise.

Once we put them in place we will need to declare our service.

Can you tell me how I start the service?

Yes, you’re right. You see, depending on the Android version we must start the service with a particular method.

If the Android version is below API 26 we must use startService. In any other case, startForegroundService is what we must use instead.

Here you can see our MainActivity, just a screen with two buttons to start and stop the service. That's all you need to start our endless service.

Remember that you can check out the complete code in this GitHub repository.

Bonus: Start the service on Android boot

Ok, we now have our endless service making network requests every minute as we wanted but then the user restarts the phone… and our service doesn’t start again… :disappointed:

Don’t worry, we can find a solution for this, too. We will create a BroadCastReceiver called StartReceiver.

Then, we’ll modify again our Android Manifest and add a new permission ( RECEIVE_BOOT_COMPLETED) and our new BroadCastReceiver.

Take into account that the service won’t be rebooted unless it was already running. That’s how we programmed it, it’s not that it has to be like that.

Anyway, if you want to test this, just spin up one emulator with Google Services in it and be sure to be running adb in root mode.

Bonus 2: Restart the service when the task is removed

Michal Materowski wrote to me with this case and its solution, so kudos for him!

Theoretically, according to Android documentation, returning RETURN_STICKY from the service’s onStartCommand method should be enough for Android to keep the foreground service running.

Michal was testing all this with a Xiaomi Note 5 with Android Pie and every time he swiped an app from recent apps, it worked flawlessly. Unfortunately, whenever he pressed the Clear all recent appsbutton (MIUI specific), the service was stopped and the notification was gone. The Clear all recent apps button was probably doing some sort of battery life optimization by killing all processes and their associated services.

He found out that Android documentation states that onStartCommand ”is called if the service is currently running and the user has removed a task that comes from the service’s application.”, so the plan was to leverage this to restart the service. Bear in mind, though, that onStartCommandis not called if the application is killed in any other way (e.g. stopped from the phone settings).

Add these lines to your service:

You can check out the original Michal Materowski’s PR with the whole code.

IMPORTANT: Michal had to manually set autostartpermission, otherwise the service was not started on boot.

According to Michal, some people mentioned that setting stopWithTask flag might help, but it didn’t make a difference for him:

Lots of kudos to Michal Materowski for his help on this case.

Enjoy!

Originally published at https://robertohuertas.com on June 29, 2019.

--

--

Roberto Huertas
Koa Health

A Barcelona-based web & mobile developer wandering through cyberspace. Organizer of @bcnrust. Currently working at Datadog.