1

Can I safely stop a Service in my main Activity's onDestroy method? I know that onDestroy is not guaranteed to be called, but I also do want to keep my Service running until the app is destroyed.

I'm thinking that maybe in all situations where the activity is destroyed, the service would also be destroyed?

pickle_inspector
  • 990
  • 1
  • 11
  • 19

2 Answers2

2

You can stop a service in the onDestroy of an activity, but to do it successfully requires either:

Running a Service in the Foreground

A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under the "Ongoing" heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.

For example, a music player that plays music from a service should be set to run in the foreground, because the user is explicitly aware of its operation. The notification in the status bar might indicate the current song and allow the user to launch an activity to interact with the music player.

or Managing Bound Services

A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves another application component and does not run in the background indefinitely

enter image description here

In all your activities, manage any resources you have created within that activity and with a null check, close them down. Like you have in your service class. If you want to override the parent onDestroy, place your custom code before super.onDestroy.

There's more detail about this here.


but I also do want to keep my Service running until the app is destroyed.

The activity can remain on the stack in the stopped state and will not be destroyed until more memory is needed. This means that there is no fixed time that the service will continue to run until the activity is destroyed.

Activity Lifecycle

If an activity is completely obscured by another activity, it is stopped. It still retains all state and member information, however, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere.

enter image description here

The entire lifetime of an activity happens between the first call to onCreate(Bundle) through to a single final call to onDestroy(). An activity will do all setup of "global" state in onCreate(), and release all remaining resources in onDestroy(). For example, if it has a thread running in the background to download data from the network, it may create that thread in onCreate() and then stop the thread in onDestroy().

To ensure that all your resources are cleaned up, you could either call finish() on the activity, or end the service in the onStop() method or use a timer in the onStop(), that will end the service or destroy the activity after x time.

The problem with calling finish() is that if the use navigates back to the activity quickly, it needs to be recreated. The problem with using stop() is if the activity is restarted the service will need to be restarted. So a timer could be a way to keep the activities natural state preserved to allow user navigation, but it would need to be stopped if the activity resumes in onResume().

For protected void onDestroy ()

Perform any final cleanup before an activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.

Community
  • 1
  • 1
  • Ok, so lets say I call unBind() in the Activity onDestroy() method. Since this is not guaranteed to be called, could I potentially have the service still running? – pickle_inspector Feb 07 '16 at 05:07
  • Ok thanks. That last part "To ensure that all your resources are cleaned up, you could either end the service in the onStop() method or use a timer in the onStop(), that will end the service after x time." is a solution but it seems a bit hacky to me. I'll have to test some stuff out. – pickle_inspector Feb 07 '16 at 05:28
  • I don't agree with line : To ensure that all your resources are cleaned up, you could either end the service in the onStop() method or use a timer in the onStop(), that will end the service after x time. Lets say finish() is called on your activity. How are you planning to stop the service in that case – Damanpreet Singh Feb 07 '16 at 05:29
  • yes thats what I'm saying. if finish is called then onStop is not guaranteed to be called. Directly onDestroy will get called hence the work done in onStop is not executed. – Damanpreet Singh Feb 07 '16 at 05:33
  • 1
    @DamanpreetSingh clean up everything in onDestroy, it will not be called only when the entire process is killed, only the data cannot be saved here, the docs say: `Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here.` – pskink Feb 07 '16 at 05:43
  • @MsYvette i have no idea if "two line answer provided here [is] as good as yours", it is not mine to decide – pskink Feb 07 '16 at 05:51
  • @MsYvette I guess pickle_inspector don't want to stop its service until app is destroyed. So, there is no question of stopping it in onstop. he doesn't want to stop service when activity is stopped. – Damanpreet Singh Feb 07 '16 at 06:12
  • sorry @MsYvette I didn't mean to say it's a hack. I just meant I wanted a simpler solution. Thanks for your input. – pickle_inspector Feb 07 '16 at 06:14
  • @MsYvette when using a bound service (in theory) all you need to do is to call `bindService` inside `Activity#onCreate`, that's all,you don't need to manage the lifecycle, when you `finish()` your activity (for example by pressing the back button) the service will be "unbound" by the OS – pskink Feb 07 '16 at 11:30
1

Yes it is safe to do it in onDestroy. Because before killing your activity background service or forground service that is bound to component will get killed by system as priority for service running in background is lesser then component you are interacting with.

  • Nice! That would simplify things a lot. I'm going to run some tests here and dig into aosp to confirm. – pickle_inspector Feb 07 '16 at 05:29
  • Ok I've just read this in the docs for Service : "If the service has been started, then its hosting process is considered to be less important than any processes that are currently visible to the user on-screen, but more important than any process not visible. Because only a few processes are generally visible to the user, this means that the service should not be killed except in low memory conditions. " So I think this answer is correct. I'm open to opinions against this though – pickle_inspector Feb 07 '16 at 05:56
  • Oops, nevermind, sorry "If there are clients bound to the service, then the service's hosting process is never less important than the most important client" – pickle_inspector Feb 07 '16 at 06:01
  • @pickle_inspector when using bound services use "local bound service" pattern, no need for any AIDL, Messengers, problems with Parcelable classes etc – pskink Feb 07 '16 at 06:04
  • @pskink I might not actually have the luxury of a local bound service since my service uses shared resources and there is another app that will likely be running on my end-user's device which will want to use it as well. Also I'm going to accept this answer since I've just read this http://developer.android.com/guide/components/bound-services.html#Additional_Notes. – pickle_inspector Feb 07 '16 at 06:12
  • @pickle_inspector are you aware of `android:sharedUserId` attribute inside `` tag? – pskink Feb 07 '16 at 06:31
  • @pskink No I wasn't aware of it. When I say shared resources I mean System resources though. Like camera etc. – pickle_inspector Feb 07 '16 at 06:38
  • @pickle_inspector i see, but still not sure why you need to run your service in a different process than your client activity runs on – pskink Feb 07 '16 at 07:57