Title: How to gracefully shutdown android service with threads running in the service
Tags: android;android-intent;service;android-activity;message
Question: The Situation:

Note: This is a followup of a previous question that takes care of how to setup the handler/message communication between activity/service. See: link

Activity connects to a started Service using binding. Activity gets a local binder with a reference to a service Handler back. Activity and Service exchange Message objects through eachothers Handlers. When user is done with App, user signals Service to quit the started Service (shutdown the service). Within the service (=mainThread) another thread is running, the serviceThread. The serviceThread is capable of running more subthreads, fully controlled by the serviceThread. Communication is handled between activity and the serviceThread, not through the mainThread of the service!!!

The Problem:

How do I gracefully shutdown the Service when inside the Service several threads are running endlessly (until I signal a message saying: "pack your backs, go home!", aka: EXIT_SERVICE.

Solution candidates:


Scenario 1: from the activity side, send a EXIT_SERVICE message to the serviceThread that is running within the service (not the mainThread!). When all subthreads of serviceThread have been cleanup/stopped send a message back to the activity indicating that it is now safe to call the stopService(Intent) method which actually stops the service. The activity can now call finish() and the App is exited gracefully.
Scenario 2: from the activity side, send a EXIT_SERVICE message to the serviceThread which will cleanup all subthreads. After that is done the serviceThread sends a message to the activity that the service is to be shutted down completely and after that message is sent, sends a message to the mainThread handler of the service to actually shutdown the service. The service receives the shutdown-message and cleans up varialbles and calls stopSelf(int).
The service is stopped and the activity knows that it can stop too, WITHOUT calling stopService(Intent)! The App is exited gracefully.
Scenario 3: from the activity side, call the stopService(Intent) method, which will deliver the Intent to the service to stop the service. In the service this Intent is intercepted (I don't know if this is possible and how to do that yet... but assuming this can be done) before the actual service code that stops the service is executed. Before the service actually stops, other code is executed first which cleans up the threads by sending a EXIT_SERVICE message to the serviceThread. After the serviceThread has cleaned up, it sends a message back to the mainThread (the service itself) and the code continues to execute the normal code that was normally executed when the Intent to stop the service wasn't intercepted. The App is exited gracefully.


So, I have three options on how to gracefully stop the Service. The problem is which scenario is the "best" (less error prone, quickest in shutting down, easiest to implement). For example: what happens when the activity is destroyed because the user switched portrait/landscape mode right at the moment the "stop service" message or Intent was sent? 

I think scenario 3 is a nice solution, because it doesn't need a lot of extra coding on the activiy side, only stopService(Intent) and finish(). The service can also be in the process of stopping while the GUI is already gone. Only thing is how to intercept the stop Intent and act upon that signal.

Please share your thoughts....

Comment: i would opt on #3.... or 2

Comment: maybe you should override onDestroy, see its dpcumentarion?

Comment: they are right: "dont call us, we will call you", in onDestroy you should clean your threads up and afaik its async operation (i mean cleaning)

Comment: sounds good (if it works as expected of course)

Comment: hmm if you join main thread with service thread you can end up with ANR but i am not sure if it applies to services

Comment: i didnt work with services that much that i could answer your questions, sorry, but there is something you get it wrong: super.onDestroy does nothing - its empty method, see Service#onDestroy implementation

Comment: That's weird: can't seem to locate where stopService(Intent) is leading to in code, only Context.stopService() which is abstract. Can't find an implementation in Eclipse Type Hierarchy for stopService(Intent)? If I can't figure out option #3, then I go for #2 because "Stop the service, if it was previously started. This is the same as calling stopService(Intent) for this particular service.", see [link](http://developer.android.com/reference/android/app/Service.html#stopSelf%28%29)

Comment: I understand that I could call onDestroy(), but it doesn't wait for all the threads to finish on time. That means the service is already gone before the threads have cleaned up. Or doesn't that matter? I could wait with calling super.onDestroy() so that I "buy some time" to finish/cleanup threads, but the docs say: "... Do not call this method directly." It doesn't say why that is. Another thing is the "public **final** void stopSelf ()". it's final, so it has to be done in onDestroy(). Is there a problem with delaying the onDestroy method before I call the super.onDestroy()?

Comment: That means the following: I receive a msg with an EXIT_SERVICE int, handle the message in the handleMessage() call stopSelf() and return true in the handleMessage() method. The android code takes over from there: it will call some internal code and then reaches the overridden onDestroy() in my service. I send msg to serviceThread "EXIT_ALL_THREADS" which takes care of msg being sent to all subthread and waits for them to respond with "I_AM_GONE" msg. Then the serviceThread knows it can safely exit the while(!cancelled) endless-loop by setting cancelled=true. Something like that?

Comment: The only thing that "worries" me is that the threads are still trying to cancel and the mainthread is already finished (super.onDestroy() is async). I hope not that the process in which the service runs is killed by android because the mainthread has stopped running while other threads (that do not sent a msg to the mainthread) are still trying to stop. Is that possible?

Comment: I could of course call stopService(Intent) also instead of sending an EXIT_SERVICE msg to the service/serviceThread. They both end up calling stopSelf().

Comment: Shouldn't I join the mainthread with the serviceThread together: one waits for the other, so that when the serviceThread ends, mainThread ends and NOT vice versa.

Comment: Good thinking! Services also run on the ui-thread == main thread. So I guess that is not an option. Can't I just NOT finish in the onDestroy with a super.onDestroy() call, but set a boolean to false, and when the serviceThread then sends an I_AM_GONE msg to the mainthread, I call the stopSelf() method again, which this time executes for the second time the onDestroy() in my service code that now also executes the if (!cancelled) { super.onDestroy() } code, making the service REALLY stop (gracefully and 100% sure in the correct order)??? What if stopSelf() implementation changes over time?

Comment: Grr. assumptions...I do that all the time (thinking how I would implement it instead of how it is implemented). So that is not going to work. When I have called stopSelf() there is no way back (it seems) because super.onDestroy() docs say: Upon return, there will be no more calls in to this Service object and it is effectively dead. Just assume that process is still alive even when mainthread is already dead?

Comment: I think I found my answer: "**In cases like this, stopService() or stopSelf() does not actually stop the service until all clients unbind.**" (see [link](http://developer.android.com/guide/components/services.html#Lifecycle)). This is good news, because I bind to the service from the MainActivity, call stopService(Intent) from MainActivity (= last activity before user exits), service enters onDestroy(), in that method I clean up my thread mess, service no longer useful (it's still there, but stopped). I call finish() in MainActivity. activity unbinds, destroys --> service gone too.

Comment: Maybe I can even send back ONE last message from serviceThread to activity (both still "in the air") that it is safe to finish the activity. That way, I know everything is cleaned up in the service. When the last message is sent, I can't communicate any longer with the serviceThread from the activity because that one is gone too and there is no need for communicating any longer. So I guess I just found my solution :)



{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 0, 'CommentCount': 16, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2013:00:10/24/13', 'FavoriteCount': 2.0, 'PostTypeId': 1, 'Tags': '<android><android-intent><service><android-activity><message>', 'Title': 'How to gracefully shutdown android service with threads running in the service', 'ViewCount': 1493, 'id': 19568388, 'user_AboutMe': '<p>If you read this, then you might be interested in my hobby: writing about-me pages ;)</p>\n', 'user_AccountId': 236688.0, 'user_DisplayName': 'user504342', 'user_Reputation': 905.0, 'user_Views': 726.0, 'user_id': 504342.0}}