How to force stop Intent Service in progress?

urSus picture urSus · Apr 19, 2013 · Viewed 7.9k times · Source

I have an intent service which downloads several gigabytes of videos. I have a "Stop" button, to stop the download if accidentally hit "Start" or whatever. I know this has been asked a couple of times but with no working answer for me.

I try to call stopService(), doesn't work. That just calls IntentService.OnDestroy(). I tried to call stopSelf() inside onDestroy, doesn't work either.

I tried to have something like a flag, but onHandleIntent doesn't get called if its already running, it waits till current work is finished and executes then. And even if this would have worked, I would have to have something like a giant if statement, that sucks

Is my only option really to rewrite it to a regular Service?

//Answer

public class SyncService extends IntentService {

    boolean isCanceled;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent.hasExtra("action")) {

            // Set the canceling flag
            isCanceled= intent.getStringExtra("action").equals("cancel");

        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        // Clean up the possible queue
        if (intent.hasExtra ("action")) {
            boolean cancel = intent.getStringExtra ("action"). Equals ("cancel");
            if (cancel) {
                return;
            }
        }

        ...

        Get your inputStream from HttpUrlConnection or whatever

        ...

        while ((bytesRead = in.read(buffer)) > 0) {
            if (isCanceled) {
                isCanceled = false;
                break;
            }

            ...
        }

    }
}

And trigger it with

Intent intent = new Intent(context, SyncService.class);
intent.putExtra("action", "cancel");
context.startService(intent);

Answer

CommonsWare picture CommonsWare · Apr 19, 2013

You have two separate issues, I would think:

  1. How to stop the current download

  2. How to stop queued up downloads, that should execute after the current one completes

The first one is going to have to be "something like a flag", that you check as you download the data. Otherwise, nothing is going to stop your download operation. If you are using a typical HttpUrlConnection recipe, you check that flag in your loop where you read from the HTTP InputStream and write to your FileOutputStream. You set that flag via a call to startService() with a particular Intent structure, identifying it as a "cancel" operation. You would need to override onStartCommand() in your IntentService, look at the Intent, use it to set the flag if it is the cancel Intent, or chain to the superclass for any other sort of Intent.

If you also may have other commands queued up (scenario #2), you would need to check that flag at the top of onHandleIntent() as well.