從doInBackground()
內調用AsyncTask.cancel(true)
之後,而不是調用onCancelled()
,Android把onPostExecute()
。但as per the documentation:AysncTask取消本身仍呼籲onPostExecute()
調用此方法將導致
onCancelled(Object)
後doInBackground(Object[])
返回被調用的UI線程上 。 調用此 方法保證onPostExecute(Object)
永遠不會被調用。
這是Android中的錯誤嗎?
更多的觀察:
- 調用
cancel(false)
從作爲 文件中指定了線程的工作。 - 從UI任務調用
cancel(true)
不不呼叫onPostExecute()
,也不會扔在logcat中看到的InterruptedException
下面痕跡。 - 從任何線程調用
cancel(false/true)
有時甚至在doInBackground()
返回之前調用onCancelled()
。這顯然是違反了文件,which states:
調用此方法將導致onCancelled(對象)被調用 UI線程後
doInBackground(Object[])
回報。
代碼:(測試Android 2.2的設備)
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的輸出
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()
爲什麼要取消'doInBackground'內的'AsyncTask'?這沒有意義。 'cancel(...)'方法故意用於允許工作線程之外的代碼(換句話說就是在UI線程上)停止執行。如果'doInBackground'中的代碼因爲任何原因需要終止本身,那麼它應該簡單地'返回'。如果您不希望'onPostExecute(...)'執行某些操作作爲僞取消的結果,那麼返回'false',否則返回'true' – Squonk 2012-04-15 17:12:25
@MisterSquonk,「取消(...)方法是故意意味着允許工作線程之外的代碼停止執行。「文檔沒有說它只能從UI線程中調用。爲什麼不重用'onCancelled()'的現有代碼,而不是使用難看的解決方法? – 2012-04-15 17:19:32
同意,文檔沒有說它應該只從UI線程調用,但這似乎最合理。我說的原因是文檔確實說'doInBackground'應定期檢查'isCancelled()'來查看它是否需要暫停自己的執行(由於調用'cancel')。如果'doInBackground'調用'cancel'是正常的,那麼'isCancelled()'是什麼意思? – Squonk 2012-04-15 17:33:12