AysncTask 取消自身仍然调用 onPostExecute() [英] AysncTask cancelling itself still calls onPostExecute()

查看:13
本文介绍了AysncTask 取消自身仍然调用 onPostExecute()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<块引用>

调用这个方法会导致onCancelled(Object)被调用doInBackground(Object[]) 返回后的 UI 线程上.调用这个方法保证 onPostExecute(Object) 永远不会被调用.

这是Android中的错误吗?

更多观察:

  1. 从任一线程调用 cancel(false) 按照文档.
  2. 从 UI 任务调用 cancel(true) 不会调用 onPostExecute(),也不会抛出 InterruptedException 在下面的 logcat 跟踪中看到.
  3. 从任何线程调用 cancel(false/true) 有时甚至在 doInBackground() 返回之前调用 onCancelled().这显然违反了文档,其中规定:莉>

<块引用>

调用这个方法会导致onCancelled(Object)被调用在 UI 线程上doInBackground(Object[]) 返回后.

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

protected Void doInBackground(Void... params) {Log.d(TAG, "开始 doInBackground()");而 (!isCancelled()) {布尔值 = 取消(真);Log.d(TAG, "cancel() 返回:" + ret);}Log.d(TAG, "从 doInBackground() 返回");返回空;}

Logcat 输出

04-15 21:38:55.519: D/MyTask(27597): 开始 doInBackground()04-15 21:38:55.589:W/AsyncTask(27597):java.lang.InterruptedException04-15 21:38:55.589: W/AsyncTask(27597): 在 java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptably(AbstractQueuedSynchronizer.java:1254)04-15 21:38:55.589:W/AsyncTask(27597):在 java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:219)04-15 21:38:55.589: W/AsyncTask(27597): 在 java.util.concurrent.FutureTask.get(FutureTask.java:82)04-15 21:38:55.589:W/AsyncTask(27597):在 android.os.AsyncTask$3.done(AsyncTask.java:196)04-15 21:38:55.589:W/AsyncTask(27597):在 java.util.concurrent.FutureTask$Sync.innerCancel(FutureTask.java:293)04-15 21:38:55.589: W/AsyncTask(27597): 在 java.util.concurrent.FutureTask.cancel(FutureTask.java:75)04-15 21:38:55.589:W/AsyncTask(27597):在 android.os.AsyncTask.cancel(AsyncTask.java:325)04-15 21:38:55.589:W/AsyncTask(27597):在 com.example.test.TestActivity$MyTask.doInBackground(TestActivity.java:31)04-15 21:38:55.589:W/AsyncTask(27597):在 com.example.test.TestActivity$MyTask.doInBackground(TestActivity.java:1)04-15 21:38:55.589:W/AsyncTask(27597):在 android.os.AsyncTask$2.call(AsyncTask.java:185)04-15 21:38:55.589: W/AsyncTask(27597): 在 java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)04-15 21:38:55.589:W/AsyncTask(27597):在 java.util.concurrent.FutureTask.run(FutureTask.java:137)04-15 21:38:55.589: W/AsyncTask(27597): 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)04-15 21:38:55.589: W/AsyncTask(27597): 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)04-15 21:38:55.589: W/AsyncTask(27597): 在 java.lang.Thread.run(Thread.java:1096)04-15 21:38:55.589:D/MyTask(27597):cancel() 返回:true04-15 21:38:55.589: D/MyTask(27597): 从 doInBackground() 返回04-15 21:38:55.659: D/MyTask(27597): onPostExecute()

解决方案

  1. 有一个例外,因为您调用cancel(true) 会向运行doInBackground() 的线程发送一个中断——但是,在这种情况下,您是从doInBackground() 内部调用cancel(true),从而导致线程立即向自身发送中断.

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

    Android 2.3.7 onPostExecute :

    <块引用>

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

    Android 4.0.1 onPostExecute :

    <块引用>

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

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:

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

解决方案

  1. 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.

  2. 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.

这篇关于AysncTask 取消自身仍然调用 onPostExecute()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆