After calling AsyncTask.cancel(true)
from within doInBackground()
, instead of calling onCancelled()
, Android calls onPostExecute()
. But as per the documentation:
Calling this method will result in
onCancelled(Object)
being invoked on the UI thread afterdoInBackground(Object[])
returns. Calling this method guarantees thatonPostExecute(Object)
is never invoked.
Is it a bug in Android?
More Observations:
cancel(false)
from either thread works as specified in the
documentation.cancel(true)
from the UI task does not call onPostExecute()
, nor does it throw the InterruptedException
seen in the logcat traces below.cancel(false/true)
from any thread sometimes calls onCancelled()
even before doInBackground()
returns. This is clearly in violation of the documentation, which states: Calling this method will result in onCancelled(Object) being invoked on the UI thread after
doInBackground(Object[])
returns.
Code: (Tested on Android 2.2 device)
protected Void doInBackground(Void... params) {
Log.d(TAG, "started doInBackground()");
while (!isCancelled()) {
boolean ret = cancel(true);
Log.d(TAG, "cancel() returned: " + ret);
}
Log.d(TAG, "returning from doInBackground()");
return null;
}
Logcat output
04-15 21:38:55.519: D/MyTask(27597): started doInBackground()
04-15 21:38:55.589: W/AsyncTask(27597): java.lang.InterruptedException
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1254)
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:219)
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.FutureTask.get(FutureTask.java:82)
04-15 21:38:55.589: W/AsyncTask(27597): at android.os.AsyncTask$3.done(AsyncTask.java:196)
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.FutureTask$Sync.innerCancel(FutureTask.java:293)
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.FutureTask.cancel(FutureTask.java:75)
04-15 21:38:55.589: W/AsyncTask(27597): at android.os.AsyncTask.cancel(AsyncTask.java:325)
04-15 21:38:55.589: W/AsyncTask(27597): at com.example.test.TestActivity$MyTask.doInBackground(TestActivity.java:31)
04-15 21:38:55.589: W/AsyncTask(27597): at com.example.test.TestActivity$MyTask.doInBackground(TestActivity.java:1)
04-15 21:38:55.589: W/AsyncTask(27597): at android.os.AsyncTask$2.call(AsyncTask.java:185)
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
04-15 21:38:55.589: W/AsyncTask(27597): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
04-15 21:38:55.589: W/AsyncTask(27597): at java.lang.Thread.run(Thread.java:1096)
04-15 21:38:55.589: D/MyTask(27597): cancel() returned: true
04-15 21:38:55.589: D/MyTask(27597): returning from doInBackground()
04-15 21:38:55.659: D/MyTask(27597): onPostExecute()
There is an exception because you call cancel(true) which sends an interrupt to the thread running doInBackground() - however, in this case, you are calling cancel(true) from within doInBackground(), thus causing the thread to immediately send an interrupt to itself.
Your code is running on Android 2 but you are quoting the docs for Android 4. The problem is that the behaviour on cancel() changed between Android 2 and Android 4.
Android 2.3.7 onPostExecute :
Runs on the UI thread after doInBackground. The specified result is the value returned by doInBackground or null if the task was cancelled or an exception occured.
Android 4.0.1 onPostExecute :
Runs on the UI thread after doInBackground. The specified result is the value returned by doInBackground. This method won't be invoked if the task was cancelled.
You should return null and treat the return in the onPostExecute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With