Ideal way to cancel an executing AsyncTask

I am running remote audio-file-fetching and audio file playback operations in a background thread using AsyncTask. A Cancellable progress bar is shown for the time the fetch operation runs.

I want to cancel/abort the AsyncTask run when the user cancels (decides against) the operation. What is the ideal way to handle such a case?


Solution 1:

Just discovered that AlertDialogs's boolean cancel(...); I've been using everywhere actually does nothing. Great.
So...

public class MyTask extends AsyncTask<Void, Void, Void> {

    private volatile boolean running = true;
    private final ProgressDialog progressDialog;

    public MyTask(Context ctx) {
        progressDialog = gimmeOne(ctx);

        progressDialog.setCancelable(true);
        progressDialog.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                // actually could set running = false; right here, but I'll
                // stick to contract.
                cancel(true);
            }
        });

    }

    @Override
    protected void onPreExecute() {
        progressDialog.show();
    }

    @Override
    protected void onCancelled() {
        running = false;
    }

    @Override
    protected Void doInBackground(Void... params) {

        while (running) {
            // does the hard work
        }
        return null;
    }

    // ...

}

Solution 2:

If you're doing computations:

  • You have to check isCancelled() periodically.

If you're doing a HTTP request:

  • Save the instance of your HttpGet or HttpPost somewhere (eg. a public field).
  • After calling cancel, call request.abort(). This will cause IOException be thrown inside your doInBackground.

In my case, I had a connector class which I used in various AsyncTasks. To keep it simple, I added a new abortAllRequests method to that class and called this method directly after calling cancel.

Solution 3:

The thing is that AsyncTask.cancel() call only calls the onCancel function in your task. This is where you want to handle the cancel request.

Here is a small task I use to trigger an update method

private class UpdateTask extends AsyncTask<Void, Void, Void> {

        private boolean running = true;

        @Override
        protected void onCancelled() {
            running = false;
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
            onUpdate();
        }

        @Override
        protected Void doInBackground(Void... params) {
             while(running) {
                 publishProgress();
             }
             return null;
        }
     }

Solution 4:

Simple: don't use an AsyncTask. AsyncTask is designed for short operations that end quickly (tens of seconds) and therefore do not need to be canceled. "Audio file playback" does not qualify. You don't even need a background thread for ordinary audio file playback.