I have an IntentService that is started from an Activity and I would like to be able to stop the service immediately from the activity with a "cancel" button in the activity. As soon as that "cancel" button is pressed, I want the service to stop executing lines of code.
I've found a number of questions similar to this (i.e. here, here, here, here), but no good answers. Activity.stopService()
and Service.stopSelf()
execute the Service.onDestroy()
method immediately but then let the code in onHandleIntent()
finish all the way through before destroying the service.
Since there is apparently no guaranteed way to terminate the service's thread immediately, the only recommended solution I can find (here) is to have a boolean member variable in the service that can be switched in the onDestroy()
method, and then have just about every line of the code in onHandleIntent()
wrapped in its own "if" clause looking at that variable. That's an awful way to write code.
Does anybody know of a better way to do this in an IntentService?
If using an
IntentService
, then I think you are stuck doing something like you describe, where theonHandleIntent()
code has to poll for its "stop" signal.If your background task is potentially long-running, and if you need to be able to stop it, I think you are better off using a plain
Service
instead. At a high level, write your Service to:AsyncTask.cancel(true)
, or have onDestroy() invokeAsyncTask.cancel(true)
.In exchange for the ability to cancel the background work, the Service takes on the following responsibilities:
doInBackground()
will have to gracefully handle InterruptedException and/or periodically check for Thread.interrupted(), and return "early".stopSelf()
is called (maybe in AsyncTask onPostExecute/onCancelled).As @budius already mentioned in his comment, you should set a boolean on the
Service
when you click that button:And in your
Intent
handling, before you do the important task of committing/sending the intent information, just use that boolean:Otherwise, the Service will do it's task of processing that
Intent
. That's how it was meant to be used, because I can't quite see how you could solve it otherwise if you look at the core code.I've used a BroadcastReceiver inside the service that simply puts a stop boolean to true. Example:
Then, from the activity call:
To stop the service.
PD: I use a boolean because In my case I stop the service while in a loop but you can probably call unregisterReceiver and stopSelf in onReceive.
PD2: Don't forget to call unregisterReceiver if the service finishes it's work normally or you'll get a leaked IntentReceiver error.