Canceling AsyncTask

Another nice usability touch we can provide for our users is the ability to cancel a task before it completes—for example, if the task depends on some user input and, after starting the execution, the user realizes that they have provided the wrong value. AsyncTask provides support for cancellation with the cancel method.

public final boolean cancel(boolean mayInterruptIfRunning)

The mayInterruptIfRunning parameter allows us to specify whether an AsyncTask thread that is in an interruptible state may actually be interrupted—for example, if our doInBackground code is performing interruptible I/O.

Simply invoking cancel is not sufficient to cause our task to finish early. We need to actively support cancellation by periodically checking the value returned from isCancelled and reacting appropriately in doInBackground.

First, let's set up our ProgressDialog to trigger the AsyncTask's cancel method by adding a few lines to onPreExecute:

progress.setCancelable(true);
progress.setOnCancelListener(
  new DialogInterface.OnCancelListener() {
    public void onCancel(DialogInterface dialog) {
      PrimesTask.this.cancel(false);
    }
  });

Now we can trigger cancel by touching outside the progress dialog, or pressing the device's back button while the dialog is visible. We'll invoke cancel with false, as we are not doing interruptible work inside the method or checking the return value of Thread.interrupted, so calling an interrupt will have no effect. We still need to check for cancellation in doInBackground, so we will modify it as follows:

protected BigInteger doInBackground(Integer... params) {
  int primeToFind = params[0];
  BigInteger prime = new BigInteger("2");
  for (int i=0; i<primeToFind; i++) {
    prime = prime.nextProbablePrime();
    int percentComplete = (int)((i * 100f)/primeToFind);
    publishProgress(percentComplete);
    if (isCancelled())
      break;
  }
  return prime;
}

The cancelled AsyncTask does not receive the onPostExecute callback. Instead, we have the opportunity to implement different behavior for a cancelled execution by implementing onCancelled. There are two variants of this callback method:

protected void onCancelled(Result result);
protected void onCancelled();

The default implementation of the parameterized onCancelled(Result result) method delegates to the onCancelled method.

If AsyncTask can provide either a complete result (such as a fully downloaded image) or nothing, then we will probably want to override the zero argument onCancelled() method.

If we are performing an incremental computation in our AsyncTask, we might choose to override the onCancelled(Result result) version so that we can make use of the result computed up to the point of cancellation.

In all cases, since onPostExecute does not get called on a canceled AsyncTask, we will want to make sure that our onCancelled callbacks update the user interface appropriately—in our example, this entails dismissing the progress dialog we opened in onPreExecute, and updating the result text.

protected void onCancelled(BigInteger result) {
  if (result != null)
    resultView.setText("cancelled at " + result.toString());
  progress.dismiss();
}

Another situation to be aware of occurs when we cancel an AsyncTask that has not yet begun its doInBackground method. If this happens, doInBackground will never be invoked, though onCancelled will still be called on the main thread.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.126.33