Po wywołaniu AsyncTask.cancel(true)
od doInBackground()
, zamiast wywoływania onCancelled()
, połączenia Android onPostExecute()
. Ale as per the documentation:AysncTask anulowanie się wciąż wywołuje onPostExecute()
Wywołanie tej metody spowoduje
onCancelled(Object)
powołano na wątku UI podoInBackground(Object[])
zwrotów. Wywołanie tej metody polega na tym, żeonPostExecute(Object)
nigdy nie jest wywoływana.
Czy to błąd w systemie Android?
More Obserwacje:
- Wywołanie
cancel(false)
z działa albo wątek, jak określono w dokumentacji . - Wywołanie
cancel(true)
od zadania UI robi nie połączeniaonPostExecute()
, ani nie rzucaćInterruptedException
widać w LogCat ślady poniżej. - Wywołanie
cancel(false/true)
z dowolnego wątku czasami wywołujeonCancelled()
jeszcze przed zwróceniemdoInBackground()
. Jest to wyraźnie sprzeczne z dokumentacją, which states:
Wywołanie tej metody spowoduje onCancelled (Object) jest wywoływana na wątku UI po
doInBackground(Object[])
zwrotów.
Kod: (testowane na urządzeniu z Androidem 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;
}
wyjście 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()
Dlaczego chcesz, aby anulować 'AsyncTask' od wewnątrz' doInBackground'? To nie ma sensu. Metoda 'cancel (...)' jest celowo przeznaczona do zatrzymania wykonywania kodu poza wątkiem roboczym (innymi słowy w wątku UI). Jeśli kod na 'doInBackground' musi się zakończyć z jakiegokolwiek powodu, powinien po prostu" return ". Jeśli nie chcesz, aby 'onPostExecute (...)' wykonywał określone akcje w wyniku pseudo-anulowania, zwróć 'false' w przeciwnym wypadku zwróć' true' – Squonk
@MisterSquonk, "Metoda anulowania (...) jest celowo ma na celu zezwolenie na kod znajdujący się poza wątkiem roboczym w celu zatrzymania egzekucji. " Dokumentacja nie mówi, że należy ją wywoływać tylko z wątku interfejsu użytkownika. Dlaczego nie użyć ponownie istniejącego kodu 'onCancelled()' zamiast używać nieestetycznych obejść? –
Zgoda, dokumentacja nie mówi, że powinna być wywołana tylko z wątku UI, ale wydaje się to najbardziej logiczne. Powodem, dla którego mówię, że dokumentacja mówi, że 'doInBackground' powinien okresowo sprawdzać' isCancelled() ', aby sprawdzić, czy musi zatrzymać swoje własne wykonanie (w wyniku wywołania' cancel '). Jeśli wywołanie 'doInBackground' wywołanie' cancel 'jest normalne, to jaki byłby punkt 'isCancelled()'? – Squonk