La respuesta dada por @Romain Guy es correcta. Sin embargo, me gustaría agregar un complemento de información y dar un puntero a una biblioteca o 2 que se pueden usar para AsyncTask de larga ejecución e incluso más para asynctasks orientados a la red.
AsyncTasks ha sido diseñado para hacer cosas en segundo plano. Y sí, puedes detenerlo usando el cancel
método. Como descargar cosas de Internet, le recomiendo encarecidamente que se ocupa de su hilo cuando es el estado de bloqueo IO . Debe organizar su descarga de la siguiente manera:
public void download() {
while( inputStream.read(buffer) != -1 && !Thread.interrupted() ) {
}
}
El uso de la Thread.interrupted
bandera ayudará a su hilo a salir correctamente de un estado io de bloqueo. Su hilo responderá mejor a una invocación del cancel
método.
Defecto de diseño de AsyncTask
Pero si su AsyncTask dura demasiado, enfrentará 2 problemas diferentes:
- Las actividades están mal vinculadas al ciclo de vida de la actividad y no obtendrá el resultado de su AsyncTask si su actividad muere. De hecho, sí, puede, pero será el camino más difícil.
- AsyncTask no está muy bien documentado. Una implementación y un uso ingenuo, aunque intuitivo, de un asynctask puede conducir rápidamente a pérdidas de memoria.
RoboSpice , la biblioteca que me gustaría presentar, utiliza un servicio en segundo plano para ejecutar este tipo de solicitudes. Ha sido diseñado para solicitudes de red. Proporciona funciones adicionales como el almacenamiento en caché automático de los resultados de las solicitudes.
Esta es la razón por la que AsyncTasks es malo para tareas de larga ejecución. El siguiente razonamiento es una adaptación de los ejercicios de las motivaciones de RoboSpice : la aplicación que explica por qué el uso de RoboSpice satisface una necesidad en la plataforma Android.
El ciclo de vida de AsyncTask y Activity
AsyncTasks no sigue el ciclo de vida de las instancias de actividad. Si inicia una AsyncTask dentro de una actividad y gira el dispositivo, la actividad se destruirá y se creará una nueva instancia. Pero AsyncTask no morirá. Seguirá viviendo hasta que se complete.
Y cuando se complete, AsyncTask no actualizará la interfaz de usuario de la nueva actividad. De hecho, actualiza la instancia anterior de la actividad que ya no se muestra. Esto puede llevar a una excepción del tipo java.lang.IllegalArgumentException: Vista no adjunta al administrador de ventanas si usa, por ejemplo, findViewById para recuperar una vista dentro de la Actividad.
Problema de pérdida de memoria
Es muy conveniente crear AsyncTasks como clases internas de sus actividades. Como AsyncTask necesitará manipular las vistas de la actividad cuando la tarea esté completa o en progreso, usar una clase interna de la actividad parece conveniente: las clases internas pueden acceder directamente a cualquier campo de la clase externa.
Sin embargo, significa que la clase interna tendrá una referencia invisible en su instancia de clase externa: la Actividad.
A largo plazo, esto produce una pérdida de memoria: si AsyncTask dura mucho, mantiene la actividad "viva" mientras que a Android le gustaría deshacerse de ella, ya que ya no se puede mostrar. La actividad no se puede recolectar como basura y ese es un mecanismo central para que Android preserve los recursos en el dispositivo.
Se perderá el progreso de su tarea
Puede utilizar algunas soluciones para crear un asynctask de ejecución prolongada y administrar su ciclo de vida de acuerdo con el ciclo de vida de la actividad. Puede cancelar AsyncTask en el método onStop de su actividad o puede dejar que su tarea asincrónica finalice y no pierda su progreso y vuelva a vincularla a la siguiente instancia de su actividad. .
Esto es posible y mostramos cómo en RobopSpice motivaciones, pero se vuelve complicado y el código no es realmente genérico. Además, aún perderá el progreso de su tarea si el usuario abandona la actividad y regresa. Este mismo problema aparece con Loaders, aunque sería un equivalente más simple a AsyncTask con la solución alternativa de vinculación mencionada anteriormente.
Usando un servicio de Android
La mejor opción es utilizar un servicio para ejecutar sus tareas en segundo plano de larga duración. Y esa es exactamente la solución propuesta por RoboSpice. Nuevamente, está diseñado para redes, pero podría extenderse a cosas no relacionadas con la red. Esta biblioteca tiene una gran cantidad de características .
Incluso puedes hacerte una idea en menos de 30 segundos gracias a una infografía .
Realmente es una muy muy mala idea usar AsyncTasks para operaciones de larga ejecución. Sin embargo, están bien para los de vida corta, como actualizar una Vista después de 1 o 2 segundos.
Te animo a que descargues la aplicación RoboSpice Motivations , que realmente explica esto en profundidad y proporciona muestras y demostraciones de las diferentes formas de hacer algunas cosas relacionadas con la red.
Si está buscando una alternativa a RoboSpice para tareas no relacionadas con la red (por ejemplo, sin almacenamiento en caché), también puede echar un vistazo a Tape .