2011-02-10 16 views
16

Ho un AsyncTask che ho interrotto durante l'evento del ciclo di vita di onPause di Activity, quindi non viene eseguito quando qualcuno lascia l'app, ma continua a funzionare nonostante questo. Ho aggiunto alcune tracce e questo frammento mostra il problema.AsyncTask Android non si fermerà quando viene annullato, perché?

Trace.d(TAG,"Task state: " + myTask.getStatus()); 
    myTask.cancel(true); 
    Trace.d(TAG,"Task state: " + myTask.getStatus()); 

Uscite:

Task state: RUNNING 
Task state: RUNNING 

Perché la cancel() metodo non avere alcun effetto sullo stato del compito? Ho notato che i documenti dicono che il metodo di cancellazione "tenterà" di interrompere l'attività, ma in quali circostanze fallirà? L'attività è sicuramente in esecuzione poiché emette l'output del registro ogni dieci secondi e, come puoi vedere sopra, il suo stato viene restituito come in esecuzione.

Aggiornamento: ho aggiunto la traccia per mostrarmi anche lo stato isCancelled() e che cambia. Quindi la chiamata per annullare (true) sta cambiando lo stato cancellato da falso a vero, ma apparentemente non ha alcun effetto sullo stato, o interrompe il thread.

+0

C'è un modo per il ciclo all'interno dell'attività per verificare se l'attività è stata annullata e semplicemente uscire dal ciclo? –

+0

Qual è il valore di ritorno da annullare? Ti ha detto che lo ha cancellato? –

+0

@Joel Sì, posso farlo, ma poiché uso il metodo cancel() in altri posti, voglio capire perché non sta facendo ciò che mi aspetto che sia –

risposta

2

ho scavato più profondo e sono ricordato che il mio thread stava chiamando un metodo piuttosto male scritta contenente questo, producendo un altro thread all'interno di quello che ho bisogno di cancellare:

public static void haveASleep(int milliseconds) 
{ 
    try 
    { 
     Thread.sleep(milliseconds); 
    } 
    catch (InterruptedException ie) 
    { 
     Trace.w(TAG,"Sleep interrupted"); 
    } 
} 

Così che cosa stava accadendo è stato che il thread AsyncTask chiama questo metodo per attendere un po ', e durante lo sleep la chiamata al metodo cancel() si verifica su AsyncTask, che causa un'eccezione nel thread sleep. Il mio codice ha catturato e assorbito in modo inappropriato quell'eccezione, invece di usarlo per chiudere AsyncTask.

La soluzione era cercare un'eccezione sul sonno e, se viene lanciata, uscire silenziosamente dal thread. L'app ora funziona come previsto, MA ...

Lo stato immediatamente dopo la chiamata del metodo cancel() rimane RUNNING, ma sospetto che sia perché in quel momento è ancora in esecuzione e il sistema operativo non lo ha ancora chiuso giù. Non ho idea se sia vero, ma questa è la mia migliore stima.

0

Anche se si conosce il modo in cui si annulla, è molto difficile determinare in quale stato verrà interrotto il thread. Quindi ti suggerisco di implementare il tuo modo sicuro di interrompere il thread, così sarai sicuro in quale stato ti stai fermando e assicurati che non ci siano perdite di memoria, ecc. Da più informazioni su come fermare un thread in java in sicurezza controllare modo questa discussione How to abort a thread in a fast and clean way in java?

+0

Sto usando AsyncTask che è un wrapper Android attorno al thread Java maneggiando, almeno in teoria, è facile avviare, gestire e interrompere i thread. Al momento sospetto che finirò per dover interrompere la discussione, ma voglio capire perché il metodo cancel() non sta facendo quello che sembra essere stato progettato per fare. –

+0

AsyncTask non è solo un wrapper Android. Il suo vantaggio principale rispetto al thread Java è che puoi facilmente aggiornarti usando i metodi che vengono eseguiti nel thread dell'interfaccia utente. Quindi AsyncTask ha lo stesso problema con l'arresto come thread Java. –

3

Ricorda che la tua attività e il tuo AsyncTask sono due thread separati. Quindi, anche se annulli AsyncTask, il codice per annullare l'attività potrebbe non essere ancora eseguito! Ecco perché stai vedendo l'AsyncTask ancora in esecuzione anche dopo aver corretto il bug. Non credo che lo stato cambierà fino al doInBackground() nel tuo AsyncTask ha completato. (In modo da assicurarsi che si sta controllando isCancelled() e tornando presto, quando sei stato annullato!)

0

Un'altra possibile trappola per verificare se si sta eseguendo in questo problema:

Assicurarsi che non sta avviando due AsyncTasks .

2
thread.cancel(true); 

Imposta solo una variabile nella classe AsyncTask. Quello che devi fare è implementare un ciclo nel tuo background task se non lo hai già fatto. Quindi controlla e interrompi il ciclo se cancel è true per ogni iterazione.

@Override 
protected Void doInBackground(Void... params) { 

    synchronized(this) { 

     for(int i = 0; i < 9000; i++) { 

      if(thread.isCancelled()) break; 

      // do stuff 

     } 

    } 

} 

Quindi basta impostarlo su annullato ogni volta che ne avete bisogno per fermarsi. Si fermerà prima della seguente iterazione.

@Override 
public void onStop() { 

    super.onStop(); 

    thread.cancel(true); 

} 

@Override 
public void onDestroy() { 

    super.onDestroy(); 

    thread.cancel(true); 

} 
+0

Che cos'è "thread"? –

Problemi correlati