Android AysncTask取消自身仍调用onPostExecute()

Android AysncTask取消自身仍调用onPostExecute(),android,android-asynctask,Android,Android Asynctask,从doInBackground()中调用AsyncTask.cancel(true)后,Android调用onPostExecute(),而不是调用onCancelled()。但是: 调用此方法将导致调用onCancelled(Object) 在doInBackground(Object[])返回后的UI线程上呼叫此 方法保证从不调用onPostExecute(对象) 这是安卓系统中的一个bug吗 更多观察结果: 从任一线程调用cancel(false)都可以按照 文件 从UI任务调用cance

doInBackground()
中调用
AsyncTask.cancel(true)
后,Android调用
onPostExecute()
,而不是调用
onCancelled()
。但是:

调用此方法将导致调用
onCancelled(Object)
doInBackground(Object[])
返回后的UI线程上呼叫此 方法保证从不调用
onPostExecute(对象)

这是安卓系统中的一个bug吗

更多观察结果:

  • 从任一线程调用
    cancel(false)
    都可以按照 文件
  • 从UI任务调用
    cancel(true)
    不会调用
    onPostExecute()
    ,也不会抛出下面logcat跟踪中看到的
    中断异常
  • 从任何线程调用
    cancel(false/true)
    有时甚至在
    doInBackground()
    返回之前调用
    onCancelled()
    。这显然违反了文件规定:
  • 调用此方法将导致调用onCancelled(对象) 在UI线程上,在
    doInBackground(对象[])之后
    返回

    代码:(在Android 2.2设备上测试)

    Logcat输出

    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()
    

    您应该返回null并在onPostExecute中处理返回

  • 有一个异常是因为调用cancel(true),它会向运行doInBackground()的线程发送中断-但是,在这种情况下,您是从doInBackground()中调用cancel(true),从而导致线程立即向自身发送中断

  • 您的代码在Android 2上运行,但您引用的是Android 4的文档。问题是cancel()的行为在Android 2和Android 4之间发生了变化

    :

    在doInBackground之后在UI线程上运行。指定的结果为 doInBackground返回的值,如果任务被取消,则返回null 或发生异常

    :

    在doInBackground之后在UI线程上运行。指定的结果为 doInBackground返回的值。如果发生以下情况,则不会调用此方法 任务被取消了


  • 为什么要从
    doInBackground
    中取消
    AsyncTask
    ?那没有道理。
    cancel(…)
    方法故意允许工作线程之外的代码(换句话说,在UI线程上)停止执行。如果
    doInBackground
    中的代码出于任何原因需要自行终止,那么它只需返回
    。如果您不希望
    onPostExecute(…)
    由于伪取消而执行某些操作,则返回
    false
    否则返回
    true
    @MisterSquonk,“cancel(…)方法故意允许工作线程之外的代码停止执行。”文档并没有说它只能从UI线程调用。为什么不重用
    onCancelled()
    的现有代码,而不是使用难看的解决方法呢?同意,文档中没有说应该只从UI线程调用它,但这似乎是最合乎逻辑的。我之所以这么说,是因为文档确实说,
    doInBackground
    应该定期检查
    isCancelled()
    ,看看它是否需要停止自己的执行(由于调用了
    cancel
    )。如果有
    doInBackground
    调用
    cancel
    是正常的,那么
    isCancelled()
    有什么意义呢?@MisterSquonk,很公平。为什么会有这种人为的怪异行为?此外,我还在“更多观察”下添加了第3点。我一直在查看Android v2.2的
    AsyncTask
    源代码。。。但我想不出答案。我可以看到
    AsyncTask
    使用
    java.util.concurrent.FutureTask
    ,这就是引发您发布的异常的原因。不过我现在找不到它的来源。我怀疑某个地方有一个小bug,我同意优雅地使用
    onCancelled
    。也许编写自己版本的
    AsyncTask
    就是答案。
    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()