2012-04-15 16 views
7

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 dopo doInBackground(Object[]) ritorni. La chiamata di questo metodo garantisce che onPostExecute(Object) non venga mai invocato.

Si tratta di un bug in Android?

più osservazioni:

  1. Calling cancel(false) da entrambi i fili funziona come specificato nella documentazione .
  2. Chiamata cancel(true) dal compito di interfaccia utente non chiamata onPostExecute(), né gettare la InterruptedException visto nel logcat tracce di seguito.
  3. Chiamare cancel(false/true) da qualsiasi thread a volte chiama onCancelled() anche prima dei resi doInBackground(). 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() 
+1

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

+0

@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? –

+1

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

risposta

3
  1. C'è un'eccezione perché si chiama annullare (vero) che invia un interrupt per il filo conduttore doInBackground() - tuttavia, in questo caso, si sta chiamando annullare (vero) dall'interno doInBackground(), quindi facendo in modo che il thread invii immediatamente un interrupt a se stesso.

  2. Il codice è in esecuzione su Android 2 ma che stai citando la documentazione per Android 4. Il problema è che il comportamento su cancel() è cambiato tra Android e Android 2 4.

    Android 2.3.7 onPostExecute:

    Viene eseguito sul thread dell'interfaccia utente dopo doInBackground. Il risultato specificato è il valore restituito da doInBackground o null se l'attività è stata annullata o si è verificata un'eccezione.

    Android 4.0.1 onPostExecute:

    Viene eseguito sul thread UI dopo doInBackground. Il risultato specificato è il valore restituito da doInBackground. Questo metodo non verrà invocato se l'attività è stata annullata.

1

Si dovrebbe restituire null e trattare il ritorno nella OnPostExecute.

Problemi correlati