Dopo aver chiamato AsyncTask.cancel(true)
dall'interno di doInBackground()
, invece di chiamare onCancelled()
, chiamate Android onPostExecute()
. Ma as per the documentation:AysncTask si annulla ancora chiamate onPostExecute()
chiamata a questo metodo si tradurrà in
onCancelled(Object)
essere invocato sul thread UI dopodoInBackground(Object[])
ritorni. La chiamata di questo metodo garantisce cheonPostExecute(Object)
non venga mai invocato.
Si tratta di un bug in Android?
più osservazioni:
- Calling
cancel(false)
da entrambi i fili funziona come specificato nella documentazione . - Chiamata
cancel(true)
dal compito di interfaccia utente non chiamataonPostExecute()
, né gettare laInterruptedException
visto nel logcat tracce di seguito. - Chiamare
cancel(false/true)
da qualsiasi thread a volte chiamaonCancelled()
anche prima dei residoInBackground()
. Questo è chiaramente in violazione della documentazione, which states:
chiamata a questo metodo si tradurrà in onCancelled (Object) viene richiamato sul thread UI dopo
doInBackground(Object[])
rendimenti.
Codice: (Testato su dispositivo 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;
}
uscita 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()
perché si vuole cancellare un 'AsyncTask' dall'interno' doInBackground'? Non ha senso. Il metodo 'cancel (...)' è intenzionalmente pensato per consentire al codice esterno al thread worker (in altre parole sul thread dell'interfaccia utente) di interrompere l'esecuzione. Se il codice in 'doInBackground' ha bisogno di terminare se stesso per qualsiasi motivo, allora dovrebbe semplicemente' return'. Se non vuoi 'onPostExecute (...)' per eseguire determinate azioni come risultato di una pseudo-cancellazione, allora restituisci 'false' altrimenti restituisci' true' – Squonk
@MisterSquonk, "Il metodo cancel (...) è intenzionalmente pensato per consentire il codice al di fuori del thread di lavoro per interrompere l'esecuzione. " La documentazione non dice che deve essere chiamata solo dal thread dell'interfaccia utente. Perché non riutilizzare il codice esistente di 'onCancelled()' invece di usare soluzioni antiestetiche? –
D'accordo, la documentazione non dice che dovrebbe essere chiamata solo dal thread dell'interfaccia utente, ma sembra più logico. La ragione per cui dico che la documentazione dice che 'doInBackground' dovrebbe periodicamente controllare' isCancelled() 'per vedere se ha bisogno di fermare la propria esecuzione (come risultato di una chiamata a' cancel'). Se la chiamata 'cancel 'di' doInBackground' è normale allora quale sarebbe il punto di 'isCancelled()'? – Squonk