2011-02-10 11 views
16

Tengo un AsyncTask que cierro en el evento del ciclo de vida onPause de Activity, por lo que no se ejecuta cuando alguien abandona la aplicación, pero continúa a pesar de esto. Agregué un seguimiento y este fragmento muestra el problema.Android AsyncTask no se detendrá cuando se cancele, ¿por qué?

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

Salidas:

Task state: RUNNING 
Task state: RUNNING 

¿Por qué el cancel() método no tiene ningún efecto sobre el estado de la tarea? Noté que los documentos dicen que el método cancelar "intentará" detener la tarea, pero ¿bajo qué circunstancias fallará? La tarea se está ejecutando definitivamente ya que está produciendo salida de registro cada diez segundos, y como puede ver arriba, su estado se devuelve como en ejecución.

Actualización: Agregué el rastreo para mostrarme el estado isCancelled() también y eso SI cambia. Por lo tanto, la llamada para cancelar (verdadero) está cambiando el estado cancelado de falso a verdadero, pero aparentemente no tiene ningún efecto en el estado o detiene el hilo.

+0

¿Hay alguna manera de que el ciclo dentro de su tarea verifique si la tarea se ha cancelado y simplemente salga del ciclo? –

+0

¿Cuál es el valor de retorno de cancelar? ¿Te dijo que lo canceló? –

+0

@Joel Sí, puedo hacer eso, pero como uso el método cancel() en otros lugares, quiero entender por qué no está haciendo lo que esperaba –

Respuesta

2

cavé más profundo y recordé que mi hilo estaba llamando a un método bastante mal escrito que contenga este, produciendo otro hilo en el interior el que necesito para cancelar:

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

Así que lo que estaba ocurriendo se que el subproceso AsyncTask llama a este método para esperar un rato, y durante el reposo se produce la llamada al método cancel() en AsyncTask, que causa una excepción en el repositorio de subprocesos. Mi código inútilmente atrapó y absorbió esa excepción, en lugar de usarlo para apagar AsyncTask.

La solución fue buscar una excepción en el modo reposo, y si se lanza, salir silenciosamente del hilo. La aplicación ahora funciona como se esperaba, PERO ...

El estado inmediatamente después de la llamada al método cancel() permanece EN EJECUCIÓN, pero sospecho que esto es porque en ese momento todavía se está ejecutando, y el sistema operativo aún no lo ha cerrado abajo. No tengo idea si eso es cierto, pero esa es mi mejor estimación.

0

Incluso si sabe cómo funciona la cancelación, es muy difícil determinar en qué estado se detendrá el hilo. Por lo tanto, sugiero que implemente su propia forma segura de detener el hilo, para estar seguro de en qué estado se está deteniendo y de que no haya pérdidas de memoria, etc. Para más información, para detener un hilo en java en un lugar seguro así que mira esto hilo How to abort a thread in a fast and clean way in java?

+0

Estoy usando AsyncTask, que es un contenedor de Android alrededor del hilo de Java el manejo, al menos en teoría, facilita el inicio, la gestión y la detención de los hilos. Por el momento sospecho que terminaré teniendo fuerza bruta para detener el hilo, pero quiero entender por qué el método cancel() no está haciendo lo que parece haber sido diseñado para hacer. –

+0

AsyncTask no es solo un contenedor de Android. Su principal ventaja sobre el hilo de Java es que puede actualizar fácilmente su GUI utilizando métodos que se ejecutan en el hilo de la interfaz de usuario. Así que AsyncTask tiene el mismo problema al detenerse como hilo Java. –

3

Tenga en cuenta que su actividad y su AsyncTask son dos hilos separados. ¡Incluso si cancela AsyncTask, el código para cancelar la tarea puede no ejecutarse todavía! Es por eso que está viendo que AsyncTask sigue ejecutándose incluso después de corregir su error. No creo que el estado cambie hasta que se complete doInBackground() en su AsyncTask. (Así que asegúrese de que está comprobando y volviendo isCancelled() temprano cuando usted ha sido cancelado!)

0

Otra posible trampa para comprobar si se está ejecutando en este problema:

Asegúrese de que no está comenzando dos AsyncTasks .

2
thread.cancel(true); 

sólo establece una variable en la clase AsyncTask. Lo que debes hacer es implementar un bucle en tu tarea de fondo si aún no lo has hecho. Luego, verifique y rompa el ciclo si la cancelación es verdadera para cada iteración.

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

    synchronized(this) { 

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

      if(thread.isCancelled()) break; 

      // do stuff 

     } 

    } 

} 

Luego, configúrelo para que se cancele siempre que lo necesite detenerlo. Luego se detendrá antes de la siguiente iteración.

@Override 
public void onStop() { 

    super.onStop(); 

    thread.cancel(true); 

} 

@Override 
public void onDestroy() { 

    super.onDestroy(); 

    thread.cancel(true); 

} 
+0

¿Qué es "hilo"? –

Cuestiones relacionadas