AysncTask cancelling itself still calls onPostExecute()

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 after doInBackground(Object[]) returns. Calling this method guarantees that onPostExecute(Object) is never invoked .

Is it a bug in Android?

More Observations:

  • Calling cancel(false) from either thread works as specified in the documentation.
  • Calling cancel(true) from the UI task does not call onPostExecute() , nor does it throw the InterruptedException seen in the logcat traces below.
  • Calling 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.


  • 您应该返回null并将onPostExecute中的返回值对待。

    链接地址: http://www.djcxy.com/p/58842.html

    上一篇: 带有DotNetOpenAuth的ASP.NET Web API

    下一篇: AysncTask取消自己仍然调用onPostExecute()