AysncTask 取消自身仍然调用 onPostExecute() [英] AysncTask cancelling itself still calls onPostExecute()
问题描述
在doInBackground()
中调用AsyncTask.cancel(true)
后,Android调用而不是
.但是根据文档:onCancelled()
onPostExecute()
调用这个方法会导致onCancelled(Object)
被调用doInBackground(Object[])
返回后的 UI 线程上.调用这个方法保证 onPostExecute(Object)
永远不会被调用.
这是Android中的错误吗?
更多观察:
- 从任一线程调用
cancel(false)
按照文档. - 从 UI 任务调用
cancel(true)
不会调用onPostExecute()
,也不会抛出InterruptedException
在下面的 logcat 跟踪中看到. - 从任何线程调用
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()
有一个例外,因为您调用cancel(true) 会向运行doInBackground() 的线程发送一个中断——但是,在这种情况下,您是从doInBackground() 内部调用cancel(true),从而导致线程立即向自身发送中断.
您的代码在 Android 2 上运行,但您引用的是 Android 4 的文档.问题在于,cancel() 的行为在 Android 2 和 Android 4 之间发生了变化.
<块引用>在 doInBackground 之后在 UI 线程上运行.指定的结果是doInBackground 返回的值,如果任务被取消则返回 null或发生异常.
<块引用>在 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 afterdoInBackground(Object[])
returns. Calling this method guarantees thatonPostExecute(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 callonPostExecute()
, nor does it throw theInterruptedException
seen in the logcat traces below. - Calling
cancel(false/true)
from any thread sometimes callsonCancelled()
even beforedoInBackground()
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.
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.
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屋!