He estado trabajando en la plataforma Android SDK, y no está claro cómo guardar el estado de una aplicación. Entonces, dada esta pequeña herramienta del ejemplo 'Hola, Android':
package com.android.hello;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class HelloAndroid extends Activity {
private TextView mTextView = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = new TextView(this);
if (savedInstanceState == null) {
mTextView.setText("Welcome to HelloAndroid!");
} else {
mTextView.setText("Welcome back.");
}
setContentView(mTextView);
}
}
Pensé que sería suficiente para el caso más simple, pero siempre responde con el primer mensaje, sin importar cómo navegue fuera de la aplicación.
Estoy seguro de que la solución es tan simple como anular onPause
o algo así, pero he estado hurgando en la documentación durante aproximadamente 30 minutos y no he encontrado nada obvio.
android
android-activity
application-state
Bernardo
fuente
fuente
Respuestas:
Debe anular
onSaveInstanceState(Bundle savedInstanceState)
y escribir los valores de estado de la aplicación que desea cambiar alBundle
parámetro de esta manera:El paquete es esencialmente una forma de almacenar un mapa NVP ("Par nombre-valor"), y se pasará a
onCreate()
y tambiénonRestoreInstanceState()
donde extraerá los valores de la actividad de esta manera:O de un fragmento.
Normalmente usaría esta técnica para almacenar valores de instancia para su aplicación (selecciones, texto no guardado, etc.).
fuente
onSaveInstanceState
casi inútil, excepto solo en el caso de cambios en la orientación de la pantalla. En casi todos los demás casos, nunca puede confiar en él y tendrá que guardar manualmente su estado de IU en otro lugar. O evitar que su aplicación sea eliminada anulando el comportamiento del botón ATRÁS. No entiendo por qué incluso lo implementaron así en primer lugar. Totalmente poco intuitivo. Y no puede tener ese paquete que le proporciona el sistema para guardar cosas, excepto en este método muy particular.View
s que han sido los identificadores asignados . De losonSaveInstanceState
documentos: "La implementación predeterminada se encarga de la mayor parte del estado de UI por instancia llamandoonSaveInstanceState()
a cada vista en la jerarquía que tiene una identificación y guardando la identificación de la vista actualmente enfocada (todo lo cual se restaura por la implementación predeterminada deonRestoreInstanceState(Bundle)
) "Esto
savedInstanceState
es solo para guardar el estado asociado con una instancia actual de una Actividad, por ejemplo, información de navegación o selección actual, de modo que si Android destruye y recrea una Actividad, puede volver como estaba antes. Consulte la documentación paraonCreate
yonSaveInstanceState
Para un estado más longevo, considere usar una base de datos SQLite, un archivo o preferencias. Ver Guardar estado persistente .
fuente
Tenga en cuenta que NO es seguro de usar
onSaveInstanceState
yonRestoreInstanceState
para datos persistentes , de acuerdo con la documentación sobre los estados de Actividad en http://developer.android.com/reference/android/app/Activity.html .El documento establece (en la sección 'Ciclo de vida de la actividad'):
En otras palabras, coloque su código de guardar / restaurar para datos persistentes en
onPause()
yonResume()
!EDITAR : Para más aclaraciones, aquí está la
onSaveInstanceState()
documentación:fuente
Mi colega escribió un artículo explicando el estado de la aplicación en dispositivos Android, incluyendo explicaciones sobre el ciclo de vida de la actividad y la información sobre el estado, cómo almacenar información sobre el estado
Bundle
y cómo guardarla en el estadoSharedPreferences
y echar un vistazo aquí .El artículo cubre tres enfoques:
Almacene datos de control de UI / variables locales para la vida útil de la aplicación (es decir, temporalmente) utilizando un paquete de estado de instancia
Almacene datos de control de UI / variables locales entre instancias de aplicación (es decir, permanentemente) utilizando preferencias compartidas
Mantener instancias de objetos vivas en la memoria entre actividades dentro de la vida útil de la aplicación utilizando una instancia retenida sin configuración
fuente
Este es un clásico 'gotcha' del desarrollo de Android. Hay dos problemas aquí:
Navegando a través de todos estos hilos, sospecho que la mayoría de las veces los desarrolladores están hablando de estos dos problemas diferentes simultáneamente ... de ahí toda la confusión y los informes de "esto no funciona para mí".
Primero, para aclarar el comportamiento 'previsto': onSaveInstance y onRestoreInstance son frágiles y solo para el estado transitorio. El uso previsto (afaict) es manejar la recreación de la actividad cuando se gira el teléfono (cambio de orientación). En otras palabras, el uso previsto es cuando su Actividad todavía está lógicamente 'en la parte superior', pero aún debe ser reinstalada por el sistema. El paquete guardado no se conserva fuera del proceso / memoria / gc, por lo que realmente no puede confiar en esto si su actividad pasa a un segundo plano. Sí, quizás la memoria de su Actividad sobrevivirá a su viaje al fondo y escapará de la GC, pero esto no es confiable (ni es predecible).
Entonces, si tiene un escenario en el que hay un "progreso del usuario" significativo o un estado que debería persistir entre los "lanzamientos" de su aplicación, la guía es usar onPause y onResume. Debe elegir y preparar una tienda persistente usted mismo.
PERO: hay un error muy confuso que complica todo esto. Los detalles están aquí:
http://code.google.com/p/android/issues/detail?id=2373
http://code.google.com/p/android/issues/detail?id=5277
Básicamente, si su aplicación se inicia con el indicador SingleTask, y luego la inicia desde la pantalla de inicio o el menú del iniciador, esa invocación posterior creará una NUEVA tarea ... efectivamente tendrá dos instancias diferentes de su aplicación habitando la misma pila ... lo cual se vuelve muy extraño muy rápido. Esto parece suceder cuando inicia su aplicación durante el desarrollo (es decir, desde Eclipse o Intellij), por lo que los desarrolladores se encuentran mucho con esto. Pero también a través de algunos de los mecanismos de actualización de la tienda de aplicaciones (por lo que también afecta a sus usuarios).
Luché a través de estos hilos durante horas antes de darme cuenta de que mi problema principal era este error, no el comportamiento del marco previsto. Una gran crítica y
solución alterna(ACTUALIZACIÓN: ver más abajo) parece ser del usuario @kaciula en esta respuesta:Comportamiento de la tecla de inicio
ACTUALIZACIÓN Junio de 2013 : meses después, finalmente encontré la solución 'correcta'. No es necesario que administre ningún indicador de aplicación de inicio con estado, puede detectarlo desde el marco y rescatarlo adecuadamente. Lo uso cerca del comienzo de mi LauncherActivity.onCreate:
fuente
onSaveInstanceState
se llama cuando el sistema necesita memoria y mata una aplicación. No se llama cuando el usuario simplemente cierra la aplicación. Así que creo que el estado de aplicación también debe ser guardado enonPause
Debe guardarse en algún almacenamiento persistente comoPreferences
oSqlite
fuente
Ambos métodos son útiles y válidos y ambos son los más adecuados para diferentes escenarios:
onSaveInstanceState()
yonRestoreInstanceState()
generalmente es adecuado.Si guarda los datos de estado de manera persistente, puede volver a cargarlos en una
onResume()
oonCreate()
(o en realidad en cualquier llamada del ciclo de vida). Esto puede o no ser un comportamiento deseado. Si lo almacena en un paquete en unInstanceState
, entonces es transitorio y solo es adecuado para almacenar datos para usar en la misma 'sesión' de usuario (uso el término sesión libremente) pero no entre 'sesiones'.No es que un enfoque sea mejor que el otro, como todo, solo es importante comprender qué comportamiento requiere y seleccionar el enfoque más apropiado.
fuente
El estado de ahorro es un error en el mejor de los casos. Si necesita guardar datos persistentes, simplemente use una base de datos SQLite . Android hace que sea MUY fácil.
Algo como esto:
Una simple llamada después de eso
fuente
Creo que encontré la respuesta. Déjame decirte lo que he hecho en palabras simples:
Supongamos que tengo dos actividades, actividad1 y actividad2 y estoy navegando de la actividad1 a la actividad2 (he realizado algunos trabajos en la actividad2) y nuevamente a la actividad 1 haciendo clic en un botón en la actividad1. Ahora, en esta etapa, quería volver a la actividad2 y quiero ver mi actividad2 en la misma condición la última vez que dejé la actividad2.
Para el escenario anterior, lo que he hecho es que en el manifiesto hice algunos cambios como este:
Y en la actividad 1 en el evento de clic de botón, he hecho así:
Y en la actividad 2 al hacer clic en el evento de botón, he hecho así:
Ahora, lo que sucederá es que cualesquiera que sean los cambios que hemos realizado en la actividad2 no se perderán, y podemos ver la actividad2 en el mismo estado en que nos fuimos anteriormente.
Creo que esta es la respuesta y esto funciona bien para mí. Corrígeme si estoy equivocado.
fuente
onSaveInstanceState()
para datos transitorios (restaurados enonCreate()
/onRestoreInstanceState()
),onPause()
para datos persistentes (restaurados enonResume()
). De los recursos técnicos de Android:fuente
Realmente
onSaveInstanceState()
se llama cuando la actividad pasa a segundo plano.Cita de los documentos: "Este método se llama antes de que una actividad pueda ser eliminada para que cuando regrese en algún momento en el futuro pueda restaurar su estado". Fuente
fuente
Para ayudar a reducir las repeticiones utilizo lo siguiente
interface
yclass
para leer / escribir en unBundle
estado de instancia para guardar.Primero, cree una interfaz que se utilizará para anotar sus variables de instancia:
Luego, cree una clase donde se usará la reflexión para guardar valores en el paquete:
Ejemplo de uso:
Nota: Este código fue adaptado de un proyecto de biblioteca llamado AndroidAutowire que está licenciado bajo la licencia MIT .
fuente
Mientras tanto, en general no uso más
El ciclo de vida es para la mayoría de las actividades demasiado complicado y no necesario.
Y Google se afirma a sí mismo, ni siquiera es confiable.
Mi forma es guardar cualquier cambio inmediatamente en las preferencias:
De alguna manera, SharedPreferences funciona de manera similar a los Bundles. Y, naturalmente, al principio, dichos valores deben leerse a partir de las preferencias.
En el caso de datos complejos, puede usar SQLite en lugar de usar preferencias.
Al aplicar este concepto, la actividad continúa utilizando el último estado guardado, independientemente de si fue una apertura inicial con reinicios intermedios o una reapertura debido a la pila posterior.
fuente
Para responder la pregunta original directamente. savedInstancestate es nulo porque su actividad nunca se vuelve a crear.
Su actividad solo se volverá a crear con un paquete de estado cuando:
Android destruirá las actividades en segundo plano cuando esté bajo presión de memoria o después de haber estado en segundo plano durante un período prolongado de tiempo.
Al probar su ejemplo de hello world, hay algunas maneras de salir y volver a la Actividad.
En la mayoría de los casos, si solo presiona inicio y luego vuelve a iniciar la aplicación, no será necesario volver a crear la actividad. Ya existe en la memoria, por lo que no se llamará a onCreate ().
Hay una opción en Configuración -> Opciones de desarrollador llamada "No mantener actividades". Cuando está habilitado, Android siempre destruirá actividades y las recreará cuando estén en segundo plano. Esta es una gran opción para dejarla habilitada cuando se desarrolla porque simula el peor de los casos. (Un dispositivo con poca memoria que recicla sus actividades todo el tiempo).
Las otras respuestas son valiosas porque le enseñan las formas correctas de almacenar el estado, pero no sentí que realmente respondieran POR QUÉ su código no funcionaba de la manera que esperaba.
fuente
Los métodos
onSaveInstanceState(bundle)
yonRestoreInstanceState(bundle)
son útiles para la persistencia de datos simplemente mientras se gira la pantalla (cambio de orientación).Ni siquiera son buenas, mientras que el cambio entre aplicaciones (ya que el
onSaveInstanceState()
se llama método, peroonCreate(bundle)
yonRestoreInstanceState(bundle)
no se invoca de nuevo.Para un uso más persistencia preferencias compartidas. Leer este artículo
fuente
onCreate
, yonRestoreInstanceState
no están siendo llamados porque elActivity
no se destruye en absoluto cuando se cambia de aplicaciones, así que no hay necesidad de restaurar cualquier cosa. Android llamaonSaveInstanceState
solo en caso de que la Actividad se destruya más tarde (lo que sucede con 100% de certeza al rotar la pantalla porque la configuración completa del dispositivo ha cambiado y la Actividad debe volver a crearse desde cero).Mi problema era que necesitaba persistencia solo durante la vida útil de la aplicación (es decir, una sola ejecución que incluye iniciar otras sub-actividades dentro de la misma aplicación y rotar el dispositivo, etc.). Intenté varias combinaciones de las respuestas anteriores, pero no obtuve lo que quería en todas las situaciones. Al final, lo que funcionó para mí fue obtener una referencia al salvadoInstanceState durante onCreate:
y usar eso para obtener el contenido de mi variable cuando lo necesite, en la línea de:
Uso
onSaveInstanceState
yonRestoreInstanceState
como se sugirió anteriormente, pero supongo que también podría usar o alternativamente mi método para guardar la variable cuando cambie (por ejemplo, usarputBoolean
)fuente
Aunque la respuesta aceptada es correcta, existe un método más rápido y fácil para guardar el estado de la Actividad en Android usando una biblioteca llamada Icepick . Icepick es un procesador de anotaciones que se encarga de todo el código repetitivo utilizado para guardar y restaurar el estado.
Haciendo algo así con Icepick:
Es lo mismo que hacer esto:
Icepick funcionará con cualquier objeto que guarde su estado con a
Bundle
.fuente
Cuando se crea una actividad, se llama al método onCreate ().
savedInstanceState es un objeto de la clase Bundle que es nulo por primera vez, pero contiene valores cuando se vuelve a crear. Para guardar el estado de la actividad, debe anular onSaveInstanceState ().
ponga sus valores en un objeto de paquete "outState" como outState.putString ("clave", "Bienvenido de nuevo") y guarde llamando a super. Cuando se destruye la actividad, su estado se guarda en el objeto Bundle y se puede restaurar después de la recreación en onCreate () o onRestoreInstanceState (). El paquete recibido en onCreate () y onRestoreInstanceState () es el mismo.
o
fuente
Básicamente, hay dos formas de implementar este cambio.
onSaveInstanceState()
yonRestoreInstanceState()
.android:configChanges="orientation|screenSize"
.Realmente no recomiendo usar el segundo método. Dado que, según mi experiencia, estaba causando que la mitad de la pantalla del dispositivo se oscureciera al girar de vertical a horizontal y viceversa.
Usando el primer método mencionado anteriormente, podemos conservar los datos cuando se cambia la orientación o se produce cualquier cambio de configuración. Sé una forma en que puede almacenar cualquier tipo de datos dentro del objeto de estado saveInstance.
Ejemplo: considere un caso si desea persistir el objeto Json. crear una clase de modelo con captadores y establecedores.
Ahora en su actividad en el método onCreate y onSaveInstanceState haga lo siguiente. Se verá algo como esto:
fuente
Aquí hay un comentario de la respuesta de Steve Moseley (por ToolmakerSteve ) que pone las cosas en perspectiva (en general, onSaveInstanceState vs onPause, east cost vs west cost saga)
fuente
Código de Kotlin:
salvar:
y luego en
onCreate()
oonRestoreInstanceState()
Agregue valores predeterminados si no desea tener Opcionales
fuente
Para obtener datos de estado de actividad almacenados
onCreate()
, primero debe guardar los datos en salvadoInstanceState anulandoSaveInstanceState(Bundle savedInstanceState)
método.Cuando
SaveInstanceState(Bundle savedInstanceState)
se llama al método de destrucción de actividad y allí guarda los datos que desea guardar. Y obtiene lo mismoonCreate()
cuando se reinicia la actividad. (SavedInstanceState no será nulo ya que ha guardado algunos datos en él antes de que se destruya la actividad)fuente
Simple rápido para resolver este problema es usar IcePick
Primero, configure la biblioteca en
app/build.gradle
Ahora, veamos este ejemplo a continuación sobre cómo guardar el estado en Actividad
Funciona para Actividades, Fragmentos o cualquier objeto que necesite serializar su estado en un Paquete (por ejemplo, ViewPresenters de mortero)
Icepick también puede generar el código de estado de instancia para Vistas personalizadas:
fuente
No estoy seguro de si mi solución está mal vista o no, pero uso un servicio vinculado para mantener el estado de ViewModel. Si lo almacena en la memoria en el servicio o si persiste y lo recupera de una base de datos SQLite depende de sus requisitos. Esto es lo que hacen los servicios de cualquier tipo, proporcionan servicios tales como el mantenimiento del estado de la aplicación y la lógica empresarial común abstracta.
Debido a las limitaciones de memoria y procesamiento inherentes a los dispositivos móviles, trato las vistas de Android de forma similar a una página web. La página no mantiene el estado, es puramente un componente de la capa de presentación cuyo único propósito es presentar el estado de la aplicación y aceptar la entrada del usuario. Las tendencias recientes en la arquitectura de aplicaciones web emplean el antiguo modelo de Modelo, Vista, Controlador (MVC), donde la página es la Vista, los datos de dominio son el modelo y el controlador se encuentra detrás de un servicio web. El mismo patrón puede emplearse en Android con la Vista siendo, bueno ... la Vista, el modelo son sus datos de dominio y el Controlador se implementa como un servicio vinculado a Android. Siempre que desee que una vista interactúe con el controlador, vincúlela al inicio / reanudar y desvincula al detener / pausar.
Este enfoque le brinda la ventaja adicional de hacer cumplir el principio de diseño de Separación de preocupaciones en el sentido de que toda la lógica empresarial de su aplicación puede trasladarse a su servicio, lo que reduce la lógica duplicada en varias vistas y permite que la vista imponga otro principio de diseño importante, la responsabilidad única.
fuente
Kotlin
Debe anular
onSaveInstanceState
yonRestoreInstanceState
almacenar y recuperar las variables que desea que sean persistentes.Gráfico del ciclo de vida
Almacenar variables
Recuperar variables
fuente
Ahora, Android proporciona ViewModels para guardar el estado, debe intentar usarlo en lugar de saveInstanceState.
fuente
Hay una manera de hacer que Android salve los estados sin implementar ningún método. Simplemente agregue esta línea a su Declaración de Manifiesto en Actividad:
Debe tener un aspecto como este:
Aquí puede encontrar más información sobre esta propiedad.
Se recomienda dejar que Android maneje esto por usted que el manejo manual.
fuente
¿Qué guardar y qué no?
Alguna vez se preguntó por qué el texto en el
EditText
se guarda automáticamente mientras cambia la orientación? Bueno, esta respuesta es para ti.Cuando una instancia de una Actividad se destruye y el Sistema recrea una nueva instancia (por ejemplo, cambio de configuración). Intenta recrearlo utilizando un conjunto de datos guardados del estado de actividad anterior ( estado de instancia ).
El estado de instancia es una colección de pares clave-valor almacenados en un
Bundle
objeto.EditText
ListView
, etc.Si necesita guardar otra variable como parte del estado de instancia, debe ANULAR el
onSavedInstanceState(Bundle savedinstaneState)
método.Por ejemplo,
int currentScore
en una GameActivityMás detalles sobre onSavedInstanceState (Bundle savedinstaneState) al guardar datos
¿Cuál elegir para restaurar el estado de la actividad?
O
Ambos métodos obtienen el mismo objeto Bundle, por lo que realmente no importa dónde escriba su lógica de restauración. La única diferencia es que, en el
onCreate(Bundle savedInstanceState)
método, deberá realizar una comprobación nula mientras no sea necesaria en este último caso. Otras respuestas ya tienen fragmentos de código. Puedes referirlos.Más detalles sobre onRestoreInstanceState (Bundle savedinstaneState)
Prima
El sistema
onSaveInstanceState(Bundle savedInstanceState)
lo invoca solo cuando el usuario tiene la intención de volver a la Actividad. Por ejemplo, está utilizando la aplicación X y de repente recibe una llamada. Se mueve a la aplicación de llamada y vuelve a la aplicación X. En este caso, elonSaveInstanceState(Bundle savedInstanceState)
, se invocará método.Pero considere esto si un usuario presiona el botón Atrás. Se supone que el usuario no tiene la intención de volver a la Actividad, por lo tanto, en este caso
onSaveInstanceState(Bundle savedInstanceState)
no será invocado por el sistema. Señale que debe considerar todos los escenarios al guardar los datos.Enlaces relevantes:
Demostración sobre comportamiento predeterminado
Documentación oficial de Android .
fuente
Ahora tiene sentido hacer 2 formas en el modelo de vista. si desea guardar el primero como una instancia guardada: puede agregar el parámetro de estado en el modelo de vista como este https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate#java
o puede guardar variables u objetos en el modelo de vista, en este caso el modelo de vista mantendrá el ciclo de vida hasta que se destruya la actividad.
fuente
puede usar
Live Data
yView Model
For Lifecycle Handel
FromJetPack
. ver esta referencia:https://developer.android.com/topic/libraries/architecture/livedata
fuente