Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AsyncTask.onCancelled() not being called after cancel(true)

Android SDK v15 running on a 2.3.6 device.

I'm having an issue where onPostExecute() is still being called when I am calling cancel() within a doInBackground() call.

Here is my code:

@Override
public String doInBackground(String... params) {
    try {
        return someMethod();
    } catch (Exception e) {
        cancel(true);
    }

    return null;
}

public String someMethod() throws Exception {
    ...
}

I am forcing someMethod() to throw an exception to test this out, and instead of onCancelled being called, I always return to onPostExecute(). If I check isCancelled() the returned value is true, so I know that cancel(true) is being executed.

Any ideas?

like image 844
PolandSpring Avatar asked Jun 23 '12 00:06

PolandSpring


2 Answers

According to the Android API document, onCancelled() is there since API level 3, while onCancelled(Object result) had been added only since API level 11. Because of that, if the platform API level is below 11, onCancelled() will be invoked always while onCancelled(Object) will be invoked always otherwise.

So, if you want to run your code on all API level 3 and above, you need to implement both methods. In order to have the same behavior you may want to store the result in an instance variable so that isCancelled() can be used as shown below:

public class MyTask extends AsyncTask<String, String, Boolean> {
  private Boolean result;
  // . . .
  @Override
  protected void onCancelled() {
    handleOnCancelled(this.result);
  }
  @Override
  protected void onCancelled(Boolean result) {
    handleOnCancelled(result);
  }
  //Both the functions will call this function
  private void handleOnCancelled(Boolean result) {
    // actual code here
  }
}

By the way, Eric's code does not likely work because the Android API doc says:

Calling the cancel() method will result in onCancelled(Object) being invoked on the UI thread after doInBackground(Object[]) returns. Calling the cancel() method guarantees that onPostExecute(Object) is never invoked.

like image 90
IdleSun Avatar answered Sep 19 '22 16:09

IdleSun


onCancelled is only supported since Android API level 11 (Honeycomb 3.0.x). This means, on an Android 2.3.6 device, it will not be called.

Your best bet is to have this in onPostExecute:

protected void onPostExecute(...) {
    if (isCancelled() && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        onCancelled();
    } else {
        // Your normal onPostExecute code
    }
}

If you want to avoid the version check, you can instead do:

protected void onPostExecute(...) {
    if (isCancelled()) {
        customCancelMethod();
    } else {
        // Your normal onPostExecute code
    }
}
protected void onCancelled() {
    customCancelMethod();
}
protected void customCancelMethod() {
    // Your cancel code
}

Hope that helps! :)

like image 27
Cat Avatar answered Sep 20 '22 16:09

Cat