Descargo algunos datos de Internet en el hilo de fondo (uso AsyncTask
) y visualizo un cuadro de diálogo de progreso durante la descarga. La orientación cambia, la actividad se reinicia y luego mi AsyncTask se completa: quiero cerrar el cuadro de diálogo de progreso e iniciar una nueva actividad. Pero llamar a despedirDialog a veces arroja una excepción (probablemente porque la Actividad fue destruida y la nueva Actividad aún no se ha iniciado).
¿Cuál es la mejor manera de manejar este tipo de problema (actualizar la interfaz de usuario desde el hilo de fondo que funciona incluso si el usuario cambia de orientación)? ¿Alguien de Google proporcionó alguna "solución oficial"?
Respuestas:
Paso # 1: Presente su
AsyncTask
unastatic
clase anidada, o una clase completamente separada, pero no una (anidada no estática) de clase interna.Paso # 2:
AsyncTask
Mantén el control aActivity
través de un miembro de datos, establece a través del constructor y un establecedor.Paso # 3: Al crear el
AsyncTask
, suministre la corrienteActivity
al constructor.Paso # 4: En
onRetainNonConfigurationInstance()
, devuelva elAsyncTask
, después de separarlo de la actividad original, que ahora se va.Paso # 5:
onCreate()
sigetLastNonConfigurationInstance()
no lo estánull
, envíalo a tuAsyncTask
clase y llama a tu setter para asociar tu nueva actividad con la tarea.Paso # 6: No se refiera al miembro de datos de actividad de
doInBackground()
.Si sigues la receta anterior, todo funcionará.
onProgressUpdate()
yonPostExecute()
se suspenden entre el inicioonRetainNonConfigurationInstance()
y el final del siguienteonCreate()
.Aquí hay un proyecto de muestra que demuestra la técnica.
Otro enfoque es deshacerse del
AsyncTask
y mover su trabajo a unIntentService
. Esto es particularmente útil si el trabajo a realizar puede ser largo y debe continuar independientemente de lo que el usuario haga en términos de actividades (por ejemplo, descargar un archivo grande). Puede usar una transmisión ordenadaIntent
para que la actividad responda al trabajo que se está realizando (si todavía está en primer plano) o genere unaNotification
para informar al usuario si el trabajo se ha realizado. Aquí hay una publicación de blog con más información sobre este patrón.fuente
onRetainNonConfigurationInstance()
está en desuso y la alternativa sugerida es usarsetRetainInstance()
, pero no devuelve un objeto. ¿Es posible manejarasyncTask
el cambio de configuración consetRetainInstance()
?Fragment
bodega elAsyncTask
. Tener elFragment
llamadosetRetainInstance(true)
sobre sí mismo. Tener laAsyncTask
única charla con elFragment
. Ahora, en un cambio de configuración,Fragment
no se destruye ni se recrea (aunque la actividad sí lo sea), por lo queAsyncTask
se retiene durante el cambio de configuración.La respuesta aceptada fue muy útil, pero no tiene un diálogo de progreso.
Afortunadamente para usted, lector, ¡he creado un ejemplo extremadamente completo y funcional de una AsyncTask con un diálogo de progreso !
fuente
Trabajé durante una semana para encontrar una solución a este dilema sin recurrir a la edición del archivo de manifiesto. Los supuestos para esta solución son:
Implementación
Deberá copiar los dos archivos que se encuentran al final de esta publicación en su espacio de trabajo. Solo asegúrate de que:
Todos tus
Activity
mensajes deben extenderseBaseActivity
En
onCreate()
,super.onCreate()
debe llamarse después de inicializar los miembros a los que suASyncTask
s debe acceder . Además, anulegetContentViewId()
para proporcionar la identificación de diseño del formulario.Anular
onCreateDialog()
como de costumbre para crear diálogos gestionados por la actividad.Consulte el código a continuación para ver una clase interna estática de muestra para realizar sus AsyncTasks. Puede almacenar su resultado en mResult para acceder más tarde.
Y finalmente, para lanzar tu nueva tarea:
¡Eso es! Espero que esta solución robusta ayude a alguien.
BaseActivity.java (organice las importaciones usted mismo)
SuperAsyncTask.java
fuente
Si.
La solución es más una propuesta de arquitectura de aplicación que un código .
Propusieron 3 patrones de diseño que permiten que una aplicación funcione sincronizada con un servidor, independientemente del estado de la aplicación (funcionará incluso si el usuario finaliza la aplicación, el usuario cambia de pantalla, la aplicación se termina, cualquier otro estado posible donde una operación de datos de fondo podría interrumpirse, esto lo cubre)
La propuesta se explica en el discurso de las aplicaciones de cliente REST de Android durante Google I / O 2010 por Virgil Dobjanschi. Dura 1 hora, pero vale la pena verlo.
La base de esto es abstraer las operaciones de red a una
Service
que funciona de forma independiente a cualquieraActivity
en la aplicación. Si está trabajando con bases de datos, el uso deContentResolver
yCursor
le proporcionaría un patrón de Observador listo para usar que es conveniente para actualizar la IU sin ninguna lógica adicional, una vez que haya actualizado su base de datos local con los datos remotos recuperados. Cualquier otro código posterior a la operación se ejecutará a través de una devolución de llamada pasada aService
(yo uso unaResultReceiver
subclase para esto).De todos modos, mi explicación es bastante vaga, definitivamente deberías ver el discurso.
fuente
Si bien la respuesta de Mark (CommonsWare) realmente funciona para los cambios de orientación, falla si la Actividad se destruye directamente (como en el caso de una llamada telefónica).
Puede manejar los cambios de orientación Y los raros eventos de Actividad destruidos utilizando un objeto Aplicación para hacer referencia a su ASyncTask.
Hay una excelente explicación del problema y la solución aquí :
El crédito va completamente a Ryan por resolver esto.
fuente
Después de 4 años, Google resolvió el problema simplemente llamando a setRetainInstance (true) en Activity onCreate. Conservará su instancia de actividad durante la rotación del dispositivo. También tengo una solución simple para Android anterior.
fuente
debe llamar a todas las acciones de actividad utilizando el controlador de actividad. Por lo tanto, si está en algún hilo, debe crear un Runnable y publicarlo utilizando el controlador de Activitie. De lo contrario, su aplicación se bloqueará a veces con una excepción fatal.
fuente
Esta es mi solución: https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog
Básicamente los pasos son:
onSaveInstanceState
para guardar la tarea si aún se está procesando.onCreate
Me sale la tarea si se guardó.onPause
descarto elProgressDialog
si se muestra.onResume
Muestro elProgressDialog
si la tarea aún se está procesando.fuente