Search code examples
androidandroid-fragmentsandroid-serviceandroid-lifecycleandroid-service-binding

Problems keeping service alive through rotate, killing when leaving app, and turning screen off in landscape


I have a service that I need to meet the following conditions

1) The service needs to be running while the app is in the foreground.

2) When the activity rotates, do not stop the service

3) The service must remain active even if you minimize the app when one specific fragment is open.

4) When the activity is stopped (not via rotate) and it is not the specific fragment, stop the service.

I'm starting/stopping my services in the onstart/onstop. I ended up using a boolean to track if the screen was rotating.

I'm starting/stopping my services like this

context.getApplicationContext().startService(intent)

context.getApplicationContext().stopService(intent)

It worked perfectly except for one situation.

When you turn the screen off in landscape, Android for some reason decides it needs to recreate the whole activity, and calls through the entire life cycle. I've reproduced this in a basic app on 4.4 and 5.0.1, and it's been shown in other threads such as this.

Problems understanding the life cycle when screen goes off and on

When it does this, the rotating/not rotating can't be relied on, and I'm guessing due to how quickly things were happening (multiple onStop/onStarts), it was causing race conditions. When I would return to the app, sometimes it worked, sometimes it would hang (no errors), sometimes two services would be running.

It became a rabbit hole where I started doing checks like, was the screen off when it came into the onStart, so the next time onStart was called it knew it was coming back in from an screen off recreation that was being flagged as rotated (since Android was now rotating it back into landscape from the portrait lock screen). It was getting ridiculous, and not working well.

One thread suggested using a headless fragment for it to survive rotation, but I still need it to stop when the app is closed, so I end up getting stuck with the same problem.

Are there any recommended ways to go about solving this? The service can't be allowed to remain active if the app is closed (except for the 1 fragment), it'll just be a huge battery drain, and it needs to survive rotations or it will interrupt things.


Solution

  • Why use a service if you don't need it to be running when the app is closed? Just fire off a background thread when the app starts and do your work there.

    UPDATE: Instead of starting your service from an Activity, you could start it from your Application class (or a descendant thereof). You could stop it when your app is backgrounded or killed and then start it again if the app is resumed.

    The most common way to do this is to keep track of how many Activities are currently in the resumed state. This means in every Activitie's onPause() and onResume() you decrement or increment this counter. If the counter is at 0, you know you app is in the background. Note: you probably want to add a delay to decrementing the counter in onPause() since there will of course be times when you transition from one Activity to another (or switch orientation) where Activity A will be paused before Activity B starts.