2012-04-15 21 views
7

doInBackground()內調用AsyncTask.cancel(true)之後,而不是調用onCancelled(),Android把onPostExecute()。但as per the documentationAysncTask取消本身仍呼籲onPostExecute()

調用此方法將導致onCancelled(Object)doInBackground(Object[])返回被調用的UI線程上 。 調用此 方法保證onPostExecute(Object)永遠不會被調用

這是Android中的錯誤嗎?

更多的觀察:

  1. 調用cancel(false)從作爲 文件中指定了線程的工作。
  2. 從UI任務調用cancel(true)呼叫onPostExecute(),也不會扔在logcat中看到的InterruptedException下面痕跡。
  3. 從任何線程調用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() 
+1

爲什麼要取消'doInBackground'內的'AsyncTask'?這沒有意義。 'cancel(...)'方法故意用於允許工作線程之外的代碼(換句話說就是在UI線程上)停止執行。如果'doInBackground'中的代碼因爲任何原因需要終止本身,那麼它應該簡單地'返回'。如果您不希望'onPostExecute(...)'執行某些操作作爲僞取消的結果,那麼返回'false',否則返回'true' – Squonk 2012-04-15 17:12:25

+0

@MisterSquonk,「取消(...)方法是故意意味着允許工作線程之外的代碼停止執行。「文檔沒有說它只能從UI線程中調用。爲什麼不重用'onCancelled()'的現有代碼,而不是使用難看的解決方法? – 2012-04-15 17:19:32

+1

同意,文檔沒有說它應該只從UI線程調用,但這似乎最合理。我說的原因是文檔確實說'doInBackground'應定期檢查'isCancelled()'來查看它是否需要暫停自己的執行(由於調用'cancel')。如果'doInBackground'調用'cancel'是正常的,那麼'isCancelled()'是什麼意思? – Squonk 2012-04-15 17:33:12

回答

3
  1. 有它發送一箇中斷運行doInBackground()線程的例外,因爲你打電話取消(真) - 然而,在這種情況下,您呼叫內doInBackground從取消(真)(),從而導致線程立即向自己發送中斷。

  2. 你的代碼是在Android上運行2,但你引用的文檔爲Android 4的問題是,在取消()行爲的Android 2和Android 4之間改變

    Android 2.3.7 onPostExecute

    在doInBackground之後的UI線程上運行。指定的結果是doInBackground返回的值 ,如果任務被取消,則返回null 或發生異常。

    Android 4.0.1 onPostExecute:doInBackground之後的UI線程上

    上運行。指定的結果是由doInBackground返回的值 。如果 任務被取消,則不會調用此方法。

1

您應該返回null和治療的onPostExecute回報。