In a previous entry, I discussed how to keep a background process alive indefinitely. i Android 11+.
The process above is guaranteed to work indefinitely. However, in Android 12 you may discover that if you do not open your app for a couple of days, your process will be killed by Android. There are a few issues that are independent from the code and which concern the way Android manages the processes n order to keep battery and processing power. I will list below the two reasons: the phone settings being set against your app, and your app being conspicuous
The process above is guaranteed to work indefinitely. However, in Android 12 you may discover that if you do not open your app for a couple of days, your process will be killed by Android. There are a few issues that are independent from the code and which concern the way Android manages the processes n order to keep battery and processing power. I will list below the two reasons: the phone settings being set against your app, and your app being conspicuous
Are your Settings set Against Your App?
There are a few permissions that allow an app to evade the battery management.
One method is to set a permission called ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. It is highly discouraged and it is a major reason for having the app rejected by Google. In my experience you can get away with it only if you are creating a medical application.
Another solution is to set manually some settings for your application. You can do automatically using a library such as TheLittleFireman. The problem with these libraries is that generally do not cover many brand specific nuances and are generally slow to update when a new version of Android comes out. These library help you to direct the user to the rigth Settings Page to tick or untick boxes. We have implemented our own library and we will make it available soon.
The other possibility is to do it manually, which is the best solution when you just want to test, at least at an initial stage.
Under Settings you can reach the Battery Optimization page, Select "All Apps" (the default is "Non Optimised" and then look for your app. Click on it and the options shown in the second figure will be presented. Select Don't Optimise and close the Settings page. This used to be enough for Samsungs and Pixels. Huawei and OnePlus also require to allow the app to run in the background.
That is however not enough if your app is not opened often by the user. I build physical activity trackers that are given to hospital patients. The patients rarely open the app but the app is required to run for over 2 weeks. The app would be killed unless I take the two steps below.
Step 1. Go to Settings > Apps, look for your app and open the screen. See the third image. Untick Pause app activity if unused (on Pixels) or remove permissions if app is unused on Samsungs.
With Android 12 however that is not enough. you need a second step. On the same page, click on Battery and tick the Unrestricted Battery Usage tickbox. See image below.
Note: it is expected that this will change further in Android 13 with the definition of classes of statuses of applications. See the full guide here.
One method is to set a permission called ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. It is highly discouraged and it is a major reason for having the app rejected by Google. In my experience you can get away with it only if you are creating a medical application.
Another solution is to set manually some settings for your application. You can do automatically using a library such as TheLittleFireman. The problem with these libraries is that generally do not cover many brand specific nuances and are generally slow to update when a new version of Android comes out. These library help you to direct the user to the rigth Settings Page to tick or untick boxes. We have implemented our own library and we will make it available soon.
The other possibility is to do it manually, which is the best solution when you just want to test, at least at an initial stage.
Under Settings you can reach the Battery Optimization page, Select "All Apps" (the default is "Non Optimised" and then look for your app. Click on it and the options shown in the second figure will be presented. Select Don't Optimise and close the Settings page. This used to be enough for Samsungs and Pixels. Huawei and OnePlus also require to allow the app to run in the background.
That is however not enough if your app is not opened often by the user. I build physical activity trackers that are given to hospital patients. The patients rarely open the app but the app is required to run for over 2 weeks. The app would be killed unless I take the two steps below.
Step 1. Go to Settings > Apps, look for your app and open the screen. See the third image. Untick Pause app activity if unused (on Pixels) or remove permissions if app is unused on Samsungs.
With Android 12 however that is not enough. you need a second step. On the same page, click on Battery and tick the Unrestricted Battery Usage tickbox. See image below.
Note: it is expected that this will change further in Android 13 with the definition of classes of statuses of applications. See the full guide here.
Is your App a Sore in the Eye of the Operating System?
Android kills an app when it needs resources, i.e. it needs either processing power or RAM.
It will select first the apps that have been unused for a while (see previous section) and among those it will choose the ones the killing of which provide the best gain, i.e. those which take a large space in memory or that use the CPU considerably.
Moreover if your app overuses wakelocks, it is also likely to be killed because wakelock keep the cpu constantly running. The code I provided previously has indeed a serious wakelock issue.
So what can we do?
It will select first the apps that have been unused for a while (see previous section) and among those it will choose the ones the killing of which provide the best gain, i.e. those which take a large space in memory or that use the CPU considerably.
Moreover if your app overuses wakelocks, it is also likely to be killed because wakelock keep the cpu constantly running. The code I provided previously has indeed a serious wakelock issue.
So what can we do?
- Reduce the memory occupation when the app is minimised,
- Try to reduce the processing to some specific moments and
- Turn off the wakelocks when we can
Reduce the Memory Allocation when the App is Minimised
It is a common mistake to keep in memory data that you do not need when the app is minimised. For example I build trackers for hospital patients which record an awful lot of data from the phone's sensors. The data is stored into the local database. The app in the database does not use RAM. When the app needs to display the summary of the user's mobility, all today's data is loaded into memory and is processed and displayed. When the app is minimised I make sure that all the data is removed from memory by setting all the data structure variables to null or empty lists. In that way the Garbage Collector will recover the space and the app's RAM occupation will be minimised. I have no reasons to keep the data into memory because the next time we will open the app, I will have to recompute the data.
Do that operation in the onPause method.
Do that operation in the onPause method.
Process only when needed
When you programme a desktop you generally do not care about processing costs, unless you are processing an enormous amount of data and or you are on an underpowered computer. For example, it is pretty typical when you receive a piece of information, to insert it immediately into the database. On a phone that is a rather heavy operation. If you collect lots of data from sensors for example, you may wan to keep a temporary data structure in memory until you have collected several readings, so to do an insertAll which is rather efficient.
Equally, you may discover that you do not need all the processing you would normally do. In the app I have provided as example, the counter does not really need to count every number. We could probably get away with counting in 10s when the app is minimised. Or we could do far better: if the increase happens every second, we could stop counting when the app is minimised and when it is reopen, we could just count the number of seconds and increment at that point. That is obviously basic code optimisation but it is important to mention it because it may be easily overlooked. Ask yourself if and to what extent you really need the background processing, so to minimise it in terms of (i) CPU usage and (ii) frequency of usage.
Equally, you may discover that you do not need all the processing you would normally do. In the app I have provided as example, the counter does not really need to count every number. We could probably get away with counting in 10s when the app is minimised. Or we could do far better: if the increase happens every second, we could stop counting when the app is minimised and when it is reopen, we could just count the number of seconds and increment at that point. That is obviously basic code optimisation but it is important to mention it because it may be easily overlooked. Ask yourself if and to what extent you really need the background processing, so to minimise it in terms of (i) CPU usage and (ii) frequency of usage.
Reduce the Use of Wakelocks
The wakelock is set in the example to run for ever. If you open the app n Android studio you will see the line acquiring the wakelock highlighted in the editor. Studio will tell you that you should really set a timeout. Why is that? Wakelocks keep the CPU on all the time. They prevent the phone from going into sleep when needed. Sleeping is a major source of battery saving. Being awake uses a lot of battery and will bring your app to the forefront of the list of apps to kill as soon as possible.
The question we should ask ourselves is: can we reduce the use of the Wakelock only to the moments I really need it?
The when will depend on your app and its logic. For example in my trackers, when the app recognises that the user is static (we spend most of our time sitting and maybe with the phone on a table), the wakelock is turned off. However, we set a wake up sensor (this is a type of sensor that, when triggered, wakes up your app if it has gone to sleep in the meantime). In our case the wakeup sensor is the Significant Motion sensor. That sensor is triggered when the user starts walking/running/cycling or starts riding a vehicle. It is very low power and we can turn off all the other rather expensive sensors (e.g. the GPS) by knowing that when the user moves, the app will be woken app and we can restart the sensors. Ask yourself: can I let the app sleep and find a way to turn it on only when needed?
The question we should ask ourselves is: can we reduce the use of the Wakelock only to the moments I really need it?
The when will depend on your app and its logic. For example in my trackers, when the app recognises that the user is static (we spend most of our time sitting and maybe with the phone on a table), the wakelock is turned off. However, we set a wake up sensor (this is a type of sensor that, when triggered, wakes up your app if it has gone to sleep in the meantime). In our case the wakeup sensor is the Significant Motion sensor. That sensor is triggered when the user starts walking/running/cycling or starts riding a vehicle. It is very low power and we can turn off all the other rather expensive sensors (e.g. the GPS) by knowing that when the user moves, the app will be woken app and we can restart the sensors. Ask yourself: can I let the app sleep and find a way to turn it on only when needed?