Ideal way to cancel an executing AsyncTask

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;
        }
     }

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;
    }

    // ...

}

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.