Citando la documentación para AsyncTask que se encuentra aquí , dice:
Lo ideal es que AsyncTasks se utilice para operaciones cortas (unos pocos segundos como máximo). Si necesita mantener los subprocesos en ejecución durante largos períodos de tiempo, se recomienda encarecidamente que utilice las diversas API proporcionadas por el paquete java.util.concurrent, como Executor, ThreadPoolExecutor y FutureTask.
Ahora surge mi pregunta: ¿por qué? La doInBackground()
función se ejecuta fuera del hilo de la interfaz de usuario, entonces, ¿qué daño hay al tener una operación de larga duración aquí?
android
android-asynctask
usuario1730789
fuente
fuente
doInBackground
congela la pantalla si no se usa una barra de progreso.Respuestas:
Es una muy buena pregunta, se necesita tiempo como programador de Android para comprender completamente el problema. De hecho, AsyncTask tiene dos problemas principales relacionados:
Dentro de la aplicación RoboSpice Motivations ( disponible en Google Play ) respondemos esa pregunta en detalle. Le dará una vista en profundidad de AsyncTasks, Loaders, sus características e inconvenientes y también le presentará una solución alternativa para solicitudes de red: RoboSpice. Las solicitudes de red son un requisito común en Android y, por naturaleza, son operaciones de larga duración. Aquí hay un extracto de la aplicación:
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, el uso de 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 porque ya no se puede mostrar. La actividad no puede recolectarse basura y ese es un mecanismo central para que Android preserve los recursos en el dispositivo.
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 realizar algunas operaciones en segundo plano.
fuente
Porque
AsyncTask
, de forma predeterminada, usa un grupo de subprocesos que usted no creó . Nunca inmovilices recursos de un grupo que no hayas creado, ya que no sabes cuáles son los requisitos de ese grupo. Y nunca inmovilice recursos de un grupo que usted no creó si la documentación para ese grupo le indica que no lo haga, como es el caso aquí.En particular, a partir de Android 3.2, el grupo de subprocesos que se usa de
AsyncTask
forma predeterminada (para las aplicaciones conandroid:targetSdkVersion
13 o superior) tiene solo un subproceso; si ata este subproceso indefinidamente, ninguna de sus otras tareas se ejecutará.fuente
Service
, simplemente use aThread
o aThreadPoolExecutor
.TimerTask
es de Java estándar, no de Android.TimerTask
se ha abandonado en gran medida a favor deScheduledExecutorService
(que, a pesar de su nombre, forma parte del estándar Java). Ninguno de los dos está vinculado a Android, por lo que aún necesita un servicio si espera que esas cosas se ejecuten en segundo plano. Y, realmente debería considerarAlarmManager
, desde Android, por lo que no necesita un servicio merodeando solo mirando el tictac del reloj.Las tareas de Aysnc son subprocesos especializados que aún están destinados a ser utilizados con la GUI de su aplicación, pero al mismo tiempo mantienen las tareas de la interfaz de usuario que requieren muchos recursos. Entonces, cuando cosas como actualizar listas, cambiar sus vistas, etc.requieran que realice algunas operaciones de recuperación o actualización, debe usar tareas asíncronas para poder mantener estas operaciones fuera del hilo de la interfaz de usuario, pero tenga en cuenta que estas operaciones todavía están conectadas a la interfaz de usuario de alguna manera .
Para las tareas de ejecución más prolongada, que no requieren la actualización de la interfaz de usuario, puede utilizar los servicios en su lugar porque pueden vivir incluso sin una interfaz de usuario.
Por lo tanto, para tareas cortas, use tareas asíncronas porque el sistema operativo puede matarlas después de que su actividad de desove muera (generalmente no morirá en medio de la operación, pero completará su tarea). Y para tareas largas y repetitivas, utilice los servicios en su lugar.
para obtener más información, consulte los hilos:
¿AsyncTask durante más de unos segundos?
y
AsyncTask no se detendrá incluso cuando la actividad se haya destruido
fuente
El problema con AsyncTask es que si se define como una clase interna no estática de la actividad, tendrá una referencia a la actividad. En el escenario donde la actividad finaliza el contenedor de la tarea asíncrona, pero el trabajo en segundo plano en AsyncTask continúa, el objeto de actividad no se recolectará como basura ya que hay una referencia a él, esto causa la pérdida de memoria.
La solución para solucionar esto es definir la tarea asíncrona como una clase de actividad interna estática y usar una referencia débil al contexto.
Pero aún así, es una buena idea usarlo para tareas en segundo plano simples y rápidas. Para desarrollar una aplicación con código limpio, es mejor usar RxJava para ejecutar tareas complejas en segundo plano y actualizar la interfaz de usuario con los resultados.
fuente