I'm trying to create an app that lets users log routes (locations/GPS). To ensure locations are logged even when the screen is off, I have created a foreground service
for the location logging. I store the locations in a Room Database
which is injected into my service using Dagger2
.
However, this service is killed by Android which is, of course, not good. I could subscribe to low memory warnings but that doesn't solve the underlying problem of my service getting killed after ~30 minutes on a modern high-end phone running Android 8.0
I have created a minimal project with only a "Hello world" activity and the service: https://github.com/RandomStuffAndCode/AndroidForegroundService
The service is started in my Application
class, and route logging is started through a Binder
:
// Application
@Override
public void onCreate() {
super.onCreate();
mComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
Intent startBackgroundIntent = new Intent();
startBackgroundIntent.setClass(this, LocationService.class);
startService(startBackgroundIntent);
}
// Binding activity
bindService(new Intent(this, LocationService.class), mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
// mConnection starts the route logging through `Binder` once connected. The binder calls startForeground()
I probably don't need the BIND_AUTO_CREATE
flag, I've been testing different flags in an attempt to not get my service killed - no luck so far.
Using the profiler it does not seem like I have any memory leaks, memory usage is stable at ~35mb:
Using adb shell dumpsys activity processes > tmp.txt
i can confirm that foregroundServices=true
and my service is listed 8th in the LRU list:
Proc # 3: prcp F/S/FGS trm: 0 31592:com.example.foregroundserviceexample/u0a93 (fg-service)
It seems like it is not possible to create a foreground service that you can trust to not get killed. So what can we do? Well...
- Put the service in a separate process, in an attempt to let Android kill the UI/Activities while leaving the service alone. Would probably help, but doesn't seem like a guarantee
- Persist everything in the service in e.g. a Room database. Every variable, every custom class, every time any of the changes and then start the service with
START_STICKY
. This seems kind of wasteful and doesn't lead to very beautiful code, but it would probably work... somewhat. Depending on how long it takes for Android to re-create the service after killing it, a large portion of locations may be lost.
Is this really the current state of doing stuff in the background on Android? Isn't there a better way?
EDIT: Whitelisting the app for battery optimization (disabling it) does not stop my service from being killed
EDIT: Using Context.startForegroundService()
to start the service does not improve the situation
EDIT: So this indeed only occurs on some devices, but it occurs consistently on them. I guess you have to make a choice of either not supporting a huge number of users or write really ugly code. Awesome.