*** please note that this blog entry has been superseded by a more recent one dedicated to Android 12+ ***
---
In a couple of previous posts I have shown how to implement a never ending service using different methods. Unfortunately those methods no longer work in Android after 11.
Android has defined a new set of constraints that require that no background or foreground services can be created when the app is not in the foreground (i.e. it is not in use by the user). This puts some severe constraints on the creation of never ending services. Especially if those services are unstable and die at some point in time.
Therefore it is imperative that:
I have developed an example that provides a service that counts constantly from zero to infinite, incrementing every 2 seconds.
The architecture is composed of:
The example uses an MVVM architecture organisation. If you are not familiar with MVVM, you should really look into it. It is the way modern Android applications are organised. It allows the separation of concerns between the View (i.e. the UI) and the model itself (in this case our counter). Model and View can communicate using LiveData defined in the ViewModel.
The full code can be found on Github. As usual for my posts the licence is MIT so you can use the code as much as you like for any purposes you want, including commercial reasons. No need to ask.
---
In a couple of previous posts I have shown how to implement a never ending service using different methods. Unfortunately those methods no longer work in Android after 11.
Android has defined a new set of constraints that require that no background or foreground services can be created when the app is not in the foreground (i.e. it is not in use by the user). This puts some severe constraints on the creation of never ending services. Especially if those services are unstable and die at some point in time.
Therefore it is imperative that:
- the services are stable and do not stop and restart: once started they must stay for as long as they are needed - it will not be possible to restart them
- the services are started at an appropriate time (i.e. at reboot or when the app is installed/reinstalled).
I have developed an example that provides a service that counts constantly from zero to infinite, incrementing every 2 seconds.
The architecture is composed of:
- a broadcast receiver receiving the message that the phone was rebooted or the app (re)installed: class RestarterBroadcastReceiver
- a coroutine worker (MainCoroutineWorker) that will be started when the broadcast is received and will launch the never ending service. In case you are unfamiliar with the concept of a co-routine worker, this is a Jetpack class that takes care of implementing a task that needs executing independently from the status of the application. Once planned, it will be executed no matter if the app is open or closed. The type of worker that we implement is of type coroutine, so it implements suspended processing, i.e. async processing. The good thing about workers is that they take care of the complexity of coping with different versions of Android, i.e. they will implement a JobService in Android>9 or a broadcast receiver + a foreground service in previous version. Our Worker starts immediately and executes urgently as we have just very short grace period for launching the service after reboot/reinstallation. The computation is executed in the Dispatch.io context, which is a context for I/O-heavy computation. This is because I have derived this example from an application doing heavy I/O in the service. You could use other Dispatches (bar the main dispatcher, as you do not want to run on the UI thread). If you are not familiar with coroutines, dispatchers and threads, you should really look into JetPack as in my view you cannot call yourself an Android programmer without knowing JetPack and Kotlin well.
- a foreground service implementing the infinite counter (CounterService)
The example uses an MVVM architecture organisation. If you are not familiar with MVVM, you should really look into it. It is the way modern Android applications are organised. It allows the separation of concerns between the View (i.e. the UI) and the model itself (in this case our counter). Model and View can communicate using LiveData defined in the ViewModel.
The full code can be found on Github. As usual for my posts the licence is MIT so you can use the code as much as you like for any purposes you want, including commercial reasons. No need to ask.
The Broadcast Receiver
The broadcast receiver will receive the message that the phone was rebooted or the app was (re-)installed and will start the CoroutineWorker
RestarterBroadcastReceiver.kt
It will first set up some constraints (well they are empty in this case), then request that the work is done immediately (expedite work) and just once. The work must be expedite; only in case the app has exhausted the quota of expedite work, it will revert to low priority work.
The it will enqueue the task and wait for it to be executed.
The it will enqueue the task and wait for it to be executed.
The coroutine worker
It will check if the service is not already running and then it will set the context to be a high I/O operation, then it will create a service intent and launch a foreground service in Android > version O (or a normal service otherwise)
MainCoroutineWorker.kt
The service
The service is a pretty standard service which first starts (by returning start_sticky in onStartCommand so that if Android kills it (and it should not) it will start again). If you need more details look at the first blog entry (the one for android<7), as it is explained quite well.
Note that the service has been quite simplified with respect to that version: there is no emergency restart in case it is killed. The launch from the Worker allows the service not to be stopped as often as it used to be normally in Android. The only part that has become overly complicated is the creation of the notification as notifications have changed over the years and you have to consider previous versions of android as well.
Note that the service has been quite simplified with respect to that version: there is no emergency restart in case it is killed. The launch from the Worker allows the service not to be stopped as often as it used to be normally in Android. The only part that has become overly complicated is the creation of the notification as notifications have changed over the years and you have to consider previous versions of android as well.
Live Data
Just a note in case the MVVM + Live Data construct confuses you. In Live Data, the UI can subscribe to a variable (typically in the ViewModel as we are using MVVM) and every time the value is set, the interface receives the results with an async callback.
MainActivity.kt
That makes the updating of the interface quite neat.
In the view Model the variable is defined as:
In the view Model the variable is defined as:
ViewModel.kt
That is: the live data tracks the counter live data in the Service. Note: the Service must define a static variable rather than a normal variable as otherwise you risk losing the connection if you e.g. recreate the service or the service is not defined yet when the viewModel is created. So use a static variable so you are sure there is just one. Just make sure that your app does not require multiple services instances at the same time, otherwise this will not work.
The part of the service incrementing the counter is pretty easy
The part of the service incrementing the counter is pretty easy
CounterService.kt
The service defines its static variable and then updates it (being live data you must access its value field, i.e. you cannot do counter++, you must increment the value in its field value as a live data variable has more additional structures than a normal variable.
That is all!
Those of you who looked at the code for Android <7 and Android 7 to 11 will realise that the code has simplified considerably thanks to the use of JetPack. However you are required to know well the latest development in Android and that is in any case a requirement for every excellent Android programmer
That is all!
Those of you who looked at the code for Android <7 and Android 7 to 11 will realise that the code has simplified considerably thanks to the use of JetPack. However you are required to know well the latest development in Android and that is in any case a requirement for every excellent Android programmer
Does your process still stop?
The process above is guaranteed to work indefinitely. However, you may discover that, in the most recent versions of Android, if you do not open your app for a couple of days, your process will be killed. There are a few issues that are independent from the code and which concern the way Android manages the processes in order to keep battery and processing power. Two main reasons: the phone settings being set against your app, and your app being too conspicuous.
These will be discussed in the next blog entry.
These will be discussed in the next blog entry.
Change Tracker
24.05.2022 improved the live data communication between viewModel and Service
06.10.2022: removed the observers when the app enters onPause - this was likely to create warnings and misbehaviour
11.10.2022: added the "Does your process still stop?"
06.10.2022: removed the observers when the app enters onPause - this was likely to create warnings and misbehaviour
11.10.2022: added the "Does your process still stop?"
Thanks
I have developed this blog entry while on a visiting professorship funded by the University of Torino in Italy. I have called the package it.torino in their honour. I am very grateful for the support and the invitation. The copyright is however mine :)
Thanks to Omar Brugna for identifying and correcting a couple of issues in the code
Thanks to Omar Brugna for identifying and correcting a couple of issues in the code