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 activi
Stopping a thread or a process immediately is often a dirty thing. However, it should be fine if your service is stateless.
Declare the service as a separate process in the manifest:
<service
android:process=":service"
...
And when you want to stop its execution, just kill that process:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
Iterator<RunningAppProcessInfo> iter = runningAppProcesses.iterator();
while(iter.hasNext()){
RunningAppProcessInfo next = iter.next();
String pricessName = getPackageName() + ":service";
if(next.processName.equals(pricessName)){
Process.killProcess(next.pid);
break;
}
}
If using an IntentService
, then I think you are stuck doing something like you describe, where the onHandleIntent()
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() invoke AsyncTask.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).context.stopService(GPSService);
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if (action.equals(Action_CANCEL)) {
stopSelf();
} else if (action.equals(Action_START)) {
//handle
}
}
Hope it works.
As @budius already mentioned in his comment, you should set a boolean on the Service
when you click that button:
// your Activity.java
public boolean onClick() {
//...
mService.performTasks = false;
mService.stopSelf();
}
And in your Intent
handling, before you do the important task of committing/sending the intent information, just use that boolean:
// your Service.java
public boolean performTasks = true;
protected void onHandleIntent(Intent intent) {
Bundle intentInfo = intent.getBundle();
if (this.performTasks) {
// Then handle the intent...
}
}
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.
In case of IntentService it does not stop or takes any other request through some intent action until its onHandleIntent
method completes the previous request.
If we try to start IntentService again with some other action, onHandleIntent
will be called only when previous intent / task is finished.
Also stopService(intent);
or stopSelf();
does not work until the onHandleIntent()
method finishes its task.
So I think here better solution is to use normal Service
here.
I hope it will help!