Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Cómo guardar el estado de la actividad de Android mediante Guardar estado de la instancia

He estado trabajando en la plataforma Android SDK, y es un poco poco claro cómo guardar el estado de una aplicación. Por lo tanto, dado este pequeño re-herramientas del ejemplo de 'Hello, 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, no importa cómo navegar lejos de la aplicación.

  • Desarrollo de juegos para Android SDK?
  • Cómo cerrar un proyecto en Android Studio?
  • ¿Cómo puedo solucionar esta versión de la biblioteca de renderizado es más reciente que su versión de ADT plug-in en eclipse
  • ¿Cuál es la forma más fácil de dibujar línea con OpenGL-ES (android)
  • No se puede agregar la vista de encabezado a la lista - setAdapter ya se ha llamado
  • Equivalente de Clean & build en Android Studio?
  • Estoy seguro de que la solución es tan simple como sobrepasar onPause o algo así, pero he estado metiéndose en la documentación durante 30 minutos o menos y no he encontrado nada obvio.

  • La aplicación de Android comienza con el teclado virtual abierto
  • Selendroid como rascador de tela
  • Android: forma correcta de utilizar onBackPressed () con Toast
  • Explorador de archivos en Android Studio
  • Firebase se bloquea en Android durante el inicio de sesión anónimo
  • ADB no responde. Si desea volver a intentarlo, mánchelo manualmente "adb.exe" y haga clic en "Reiniciar"
  • 25 Solutions collect form web for “Cómo guardar el estado de la actividad de Android mediante Guardar estado de la instancia”

    onSaveInstanceState(Bundle savedInstanceState) sustituir onSaveInstanceState(Bundle savedInstanceState) y escribir los valores de estado de la aplicación que desea cambiar al parámetro Bundle siguiente manera:

     @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // Save UI state changes to the savedInstanceState. // This bundle will be passed to onCreate if the process is // killed and restarted. savedInstanceState.putBoolean("MyBoolean", true); savedInstanceState.putDouble("myDouble", 1.9); savedInstanceState.putInt("MyInt", 1); savedInstanceState.putString("MyString", "Welcome back to Android"); // etc. } 

    El paquete es esencialmente una forma de almacenar un mapa NVP ("nombre-par de valores"), y se pasará a onCreate() y también onRestoreInstanceState() donde se extraen los valores como este:

     @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // Restore UI state from the savedInstanceState. // This bundle has also been passed to onCreate. boolean myBoolean = savedInstanceState.getBoolean("MyBoolean"); double myDouble = savedInstanceState.getDouble("myDouble"); int myInt = savedInstanceState.getInt("MyInt"); String myString = savedInstanceState.getString("MyString"); } 

    Por lo general, utilizaría esta técnica para almacenar valores de instancia para su aplicación (selecciones, texto no guardado, etc.).

    El savedInstanceState es sólo para guardar el estado asociado con una instancia actual de una Actividad, por ejemplo la información actual de navegación o selección, de modo que si Android destruye y recrea una Actividad, puede volver como estaba antes. Consulte la documentación de onCreate y onSaveInstanceState

    Para un estado de vida más larga, considere el uso de una base de datos SQLite, un archivo o preferencias. Consulte Ahorro de estado persistente .

    Tenga en cuenta que NO es seguro utilizar onSaveInstanceState y onRestoreInstanceState para obtener 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 indica (en la sección 'Ciclo de vida de la actividad'):

    Tenga en cuenta que es importante guardar los datos persistentes en onPause() lugar de onSaveInstanceState(Bundle) porque el último no forma parte de las devoluciones de llamada del ciclo de vida, por lo que no se llamará en todas las situaciones descritas en su documentación.

    En otras palabras, ponga su código de guardar / restaurar para datos persistentes en onPause() y onResume() !

    EDIT : Para mayor aclaración, aquí está la documentación onSaveInstanceState() :

    Este método se llama antes de que una actividad se pueda matar de modo que cuando vuelva algún tiempo en el futuro pueda restaurar su estado. Por ejemplo, si la actividad B se ejecuta antes de la actividad A y en algún momento la actividad A se destruye para recuperar recursos, la actividad A tendrá la oportunidad de guardar el estado actual de su interfaz de usuario a través de este método para que cuando el usuario regrese A la actividad A, el estado de la interfaz de usuario puede restaurarse mediante onCreate(Bundle) o onRestoreInstanceState(Bundle) .

    Mi colega escribió un artículo explicando el estado de la aplicación en los dispositivos Android, incluyendo explicaciones sobre el ciclo de vida de la actividad y la información estatal, cómo almacenar la información del estado y el ahorro en el Bundle estatal y las SharedPreferences y echa un vistazo aquí .

    El artículo abarca tres enfoques:

    Almacenar los datos de control varible / UI locales para la vida útil de la aplicación (es decir, temporalmente) utilizando el paquete de estado de instancia

     [Code sample – Store State in State Bundle] @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Store UI state to the savedInstanceState. // This bundle will be passed to onCreate on next call. EditText txtName = (EditText)findViewById(R.id.txtName); String strName = txtName.getText().toString(); EditText txtEmail = (EditText)findViewById(R.id.txtEmail); String strEmail = txtEmail.getText().toString(); CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC); boolean blnTandC = chkTandC.isChecked(); savedInstanceState.putString(“Name”, strName); savedInstanceState.putString(“Email”, strEmail); savedInstanceState.putBoolean(“TandC”, blnTandC); super.onSaveInstanceState(savedInstanceState); } 

    Almacenar los datos de control varible / UI locales entre instancias de aplicación (es decir permanentemente) usando Preferencias Compartidas

     [Code sample – Store State in SharedPreferences] @Override protected void onPause() { super.onPause(); // Store values between instances here SharedPreferences preferences = getPreferences(MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); // Put the values from the UI EditText txtName = (EditText)findViewById(R.id.txtName); String strName = txtName.getText().toString(); EditText txtEmail = (EditText)findViewById(R.id.txtEmail); String strEmail = txtEmail.getText().toString(); CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC); boolean blnTandC = chkTandC.isChecked(); editor.putString(“Name”, strName); // value to store editor.putString(“Email”, strEmail); // value to store editor.putBoolean(“TandC”, blnTandC); // value to store // Commit to storage editor.commit(); } 

    Mantenimiento de las instancias de objeto en la memoria entre actividades dentro de la vida útil de la aplicación mediante la instancia retenida de no configuración

     [Code sample – store object instance] private cMyClassType moInstanceOfAClass;// Store the instance of an object @Override public Object onRetainNonConfigurationInstance() { if (moInstanceOfAClass != null) // Check that the object exists return(moInstanceOfAClass); return super.onRetainNonConfigurationInstance(); } 

    Este es un clásico 'gotcha' del desarrollo de Android. Hay dos problemas aquí:

    • Hay un sutil bug de Framework Android que complica enormemente la gestión de la pila de aplicaciones durante el desarrollo, al menos en las versiones de legado (no totalmente seguro si / cuándo / cómo se arregló). Voy a discutir este error a continuación.
    • La forma "normal" o pretendida de gestionar este problema es, en sí misma, bastante complicada con la dualidad de onPause / onResume y onSaveInstanceState / onRestoreInstanceState

    Navegando a través de todos estos hilos, sospecho que gran parte del tiempo los desarrolladores están hablando de estos dos temas diferentes al mismo tiempo … por lo tanto toda la confusión y los informes de "esto no funciona para mí".

    En primer lugar, para aclarar el comportamiento 'pretendido': onSaveInstance y onRestoreInstance son frágiles y sólo para el estado transitorio. El uso previsto (afaict) es manejar recreación de actividad cuando el teléfono es girado (cambio de orientación). En otras palabras, el uso previsto es cuando su actividad está todavía lógicamente 'en la parte superior', pero todavía debe ser reinstantiated por el sistema. El paquete guardado no se mantiene fuera del proceso / memory / gc, por lo que realmente no puede confiar en esto si su actividad va al fondo. Sí, tal vez la memoria de su Actividad sobrevivirá a su viaje al fondo y escapará a la GC, pero esto no es confiable (ni tampoco es predecible).

    Por lo tanto, si tiene un escenario en el que exista "progreso del usuario" significativo o estado que deba persistir entre "lanzamientos" de su aplicación, la guía es usar onPause y onResume. Usted debe elegir y preparar un almacén 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 ejecuta con el indicador SingleTask y, a continuación, lo inicia desde la pantalla de inicio o el menú del lanzador, esa invocación posterior creará una NUEVA tarea … tendrá efectivamente dos instancias diferentes de su aplicación Habitar la misma pila … que se pone muy extraño muy rápido. Esto parece suceder cuando se inicia su aplicación durante el desarrollo (es decir, desde Eclipse o Intellij), por lo que los desarrolladores se encuentran con esto mucho. 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 los usuarios).

    He luchado a través de estos hilos durante horas antes de que me di cuenta de que mi problema principal era este error, no el comportamiento marco previsto. Una gran escritura y Solución alternativa (UPDATE: ver más abajo) parece ser del usuario @ kaciula en esta respuesta:

    Comportamiento de la tecla principal de inicio

    UPDATE Junio ​​2013 : Meses después, finalmente he encontrado la solución 'correcta'. No es necesario gestionar ninguna bandera de estado iniciado, puede detectar esto desde el marco y la fianza apropiadamente. Yo uso esto cerca del principio de mi LauncherActivity.onCreate:

     if (!isTaskRoot()) { Intent intent = getIntent(); String action = intent.getAction(); if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) { finish(); return; } } 

    onSaveInstanceState se llama cuando el sistema necesita memoria y mata una aplicación. No se llama cuando el usuario acaba de cerrar la aplicación. Así que creo que el estado de la aplicación también debe guardarse en onPause Debe guardarse en algún almacenamiento persistente como Preferences o Sqlite

    Ambos métodos son útiles y válidos y ambos son los más adecuados para diferentes escenarios:

    1. El usuario finaliza la aplicación y la vuelve a abrir posteriormente, pero la aplicación necesita volver a cargar datos de la última sesión, lo que requiere un enfoque de almacenamiento persistente, como el uso de SQLite.
    2. El usuario cambia de aplicación y luego vuelve al original y quiere recoger donde lo dejó – guardar y restaurar los datos del paquete (como los datos del estado de la aplicación) en onSaveInstanceState() y onRestoreInstanceState() suele ser adecuado.

    Si guarda los datos de estado de forma persistente, puede volver a cargarse en un onResume() o onCreate() (o en cualquier llamada al ciclo de vida). Esto puede o no ser el comportamiento deseado. Si lo almacena en un paquete en un InstanceState , entonces es transitorio y sólo es adecuado para almacenar datos para su uso en la misma sesión de usuario (utilizo la sesión de términos de forma holgada) pero no entre sesiones.

    No es que un enfoque sea mejor que el otro, como todo, es importante entender qué comportamiento usted requiere y seleccionar el enfoque más apropiado.

    El estado del ahorro es un kludge en el mejor en lo que a mí respecta. Si necesita guardar datos persistentes, simplemente use una base de datos SQLite . Android hace SOOO fácil.

    Algo como esto:

     import java.util.Date; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class dataHelper { private static final String DATABASE_NAME = "autoMate.db"; private static final int DATABASE_VERSION = 1; private Context context; private SQLiteDatabase db; private OpenHelper oh ; public dataHelper(Context context) { this.context = context; this.oh = new OpenHelper(this.context); this.db = oh.getWritableDatabase(); } public void close() { db.close(); oh.close(); db = null; oh = null; SQLiteDatabase.releaseMemory(); } public void setCode(String codeName, Object codeValue, String codeDataType) { Cursor codeRow = db.rawQuery("SELECT * FROM code WHERE codeName = '"+ codeName + "'", null); String cv = "" ; if (codeDataType.toLowerCase().trim().equals("long") == true) { cv = String.valueOf(codeValue); } else if (codeDataType.toLowerCase().trim().equals("int") == true) { cv = String.valueOf(codeValue); } else if (codeDataType.toLowerCase().trim().equals("date") == true) { cv = String.valueOf(((Date)codeValue).getTime()); } else if (codeDataType.toLowerCase().trim().equals("boolean") == true) { String.valueOf(codeValue); } else { cv = String.valueOf(codeValue); } if(codeRow.getCount() > 0) //exists-- update { db.execSQL("update code set codeValue = '" + cv + "' where codeName = '" + codeName + "'"); } else // does not exist, insert { db.execSQL("INSERT INTO code (codeName, codeValue, codeDataType) VALUES(" + "'" + codeName + "'," + "'" + cv + "'," + "'" + codeDataType + "')" ); } } public Object getCode(String codeName, Object defaultValue) { //Check to see if it already exists String codeValue = ""; String codeDataType = ""; boolean found = false; Cursor codeRow = db.rawQuery("SELECT * FROM code WHERE codeName = '"+ codeName + "'", null); if (codeRow.moveToFirst()) { codeValue = codeRow.getString(codeRow.getColumnIndex("codeValue")); codeDataType = codeRow.getString(codeRow.getColumnIndex("codeDataType")); found = true; } if (found == false) { return defaultValue; } else if (codeDataType.toLowerCase().trim().equals("long") == true) { if (codeValue.equals("") == true) { return (long)0; } return Long.parseLong(codeValue); } else if (codeDataType.toLowerCase().trim().equals("int") == true) { if (codeValue.equals("") == true) { return (int)0; } return Integer.parseInt(codeValue); } else if (codeDataType.toLowerCase().trim().equals("date") == true) { if (codeValue.equals("") == true) { return null; } return new Date(Long.parseLong(codeValue)); } else if (codeDataType.toLowerCase().trim().equals("boolean") == true) { if (codeValue.equals("") == true) { return false; } return Boolean.parseBoolean(codeValue); } else { return (String)codeValue; } } private static class OpenHelper extends SQLiteOpenHelper { OpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS code" + "(id INTEGER PRIMARY KEY, codeName TEXT, codeValue TEXT, codeDataType TEXT)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } } 

    Una simple llamada después de eso

     dataHelper dh = new dataHelper(getBaseContext()); String status = (String) dh.getCode("appState", "safetyDisabled"); Date serviceStart = (Date) dh.getCode("serviceStartTime", null); dh.close(); dh = null; 

    Creo que encontré la respuesta. Déjeme decir lo que he hecho en palabras simples:

    Supongamos que tengo dos actividades, activity1 y activity2 y estoy navegando de activity1 a activity2 (he hecho algunos trabajos en activity2) y de nuevo a la actividad 1 haciendo clic en un botón en activity1. Ahora, en esta etapa, quería volver a la actividad2 y quiero ver mi actividad2 en la misma condición cuando dejé la última actividad2.

    Para el escenario anterior lo que he hecho es que en el manifiesto he hecho algunos cambios como este:

     <activity android:name=".activity2" android:alwaysRetainTaskState="true" android:launchMode="singleInstance"> </activity> 

    Y en la actividad1 en el botón haga clic en el evento que he hecho así:

     Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); intent.setClassName(this,"com.mainscreen.activity2"); startActivity(intent); 

    Y en activity2 en el botón haga clic en el evento que he hecho así:

     Intent intent=new Intent(); intent.setClassName(this,"com.mainscreen.activity1"); startActivity(intent); 

    Ahora bien, lo que sucederá es que, independientemente de los cambios que hayamos hecho en la actividad2, no se pierdan, y podemos ver la actividad2 en el mismo estado que dejamos anteriormente.

    Creo que esta es la respuesta y esto funciona bien para mí. Corrígeme si estoy equivocado.

    onSaveInstanceState() para datos transitorios (restaurado en onCreate() / onRestoreInstanceState() ), onPause() para datos persistentes (restaurado en onResume() ). Desde los recursos técnicos de Android:

    Android se llama a onSaveInstanceState () si la actividad se está deteniendo y se puede matar antes de que se reanude! Esto significa que debe almacenar cualquier estado necesario para reinicializarse a la misma condición cuando se reinicie la Actividad. Es la contraparte del método onCreate () y, de hecho, el conjunto savedInstanceState pasó a onCreate () es el mismo Bundle que se construye como outState en el método onSaveInstanceState ().

    OnPause () y onResume () también son métodos complementarios. OnPause () siempre se llama cuando la actividad termina, incluso si instigamos que (con una llamada finish () por ejemplo). Usaremos esto para guardar la nota actual de nuevo en la base de datos. La buena práctica es liberar todos los recursos que se pueden liberar durante una onPause (), así, para tomar menos recursos cuando en el estado pasivo.

    Realmente onSaveInstance state callen cuando la Actividad pasa al fondo

    Cita de los documentos: "el método onSaveInstanceState(Bundle) se llama antes de colocar la actividad en un estado de fondo como"

    Para ayudar a reducir boilerplate utilizo la siguiente interface y class para leer / escribir en un Bundle para guardar el estado de la instancia.


    En primer lugar, cree una interfaz que se utilizará para anotar sus variables de instancia:

     import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD }) public @interface SaveInstance { } 

    A continuación, cree una clase donde se usará la reflexión para guardar valores en el lote:

     import android.app.Activity; import android.app.Fragment; import android.os.Bundle; import android.os.Parcelable; import android.util.Log; import java.io.Serializable; import java.lang.reflect.Field; /** * Save and load fields to/from a {@link Bundle}. All fields should be annotated with {@link * SaveInstance}.</p> */ public class Icicle { private static final String TAG = "Icicle"; /** * Find all fields with the {@link SaveInstance} annotation and add them to the {@link Bundle}. * * @param outState * The bundle from {@link Activity#onSaveInstanceState(Bundle)} or {@link * Fragment#onSaveInstanceState(Bundle)} * @param classInstance * The object to access the fields which have the {@link SaveInstance} annotation. * @see #load(Bundle, Object) */ public static void save(Bundle outState, Object classInstance) { save(outState, classInstance, classInstance.getClass()); } /** * Find all fields with the {@link SaveInstance} annotation and add them to the {@link Bundle}. * * @param outState * The bundle from {@link Activity#onSaveInstanceState(Bundle)} or {@link * Fragment#onSaveInstanceState(Bundle)} * @param classInstance * The object to access the fields which have the {@link SaveInstance} annotation. * @param baseClass * Base class, used to get all superclasses of the instance. * @see #load(Bundle, Object, Class) */ public static void save(Bundle outState, Object classInstance, Class<?> baseClass) { if (outState == null) { return; } Class<?> clazz = classInstance.getClass(); while (baseClass.isAssignableFrom(clazz)) { String className = clazz.getName(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(SaveInstance.class)) { field.setAccessible(true); String key = className + "#" + field.getName(); try { Object value = field.get(classInstance); if (value instanceof Parcelable) { outState.putParcelable(key, (Parcelable) value); } else if (value instanceof Serializable) { outState.putSerializable(key, (Serializable) value); } } catch (Throwable t) { Log.d(TAG, "The field '" + key + "' was not added to the bundle"); } } } clazz = clazz.getSuperclass(); } } /** * Load all saved fields that have the {@link SaveInstance} annotation. * * @param savedInstanceState * The saved-instance {@link Bundle} from an {@link Activity} or {@link Fragment}. * @param classInstance * The object to access the fields which have the {@link SaveInstance} annotation. * @see #save(Bundle, Object) */ public static void load(Bundle savedInstanceState, Object classInstance) { load(savedInstanceState, classInstance, classInstance.getClass()); } /** * Load all saved fields that have the {@link SaveInstance} annotation. * * @param savedInstanceState * The saved-instance {@link Bundle} from an {@link Activity} or {@link Fragment}. * @param classInstance * The object to access the fields which have the {@link SaveInstance} annotation. * @param baseClass * Base class, used to get all superclasses of the instance. * @see #save(Bundle, Object, Class) */ public static void load(Bundle savedInstanceState, Object classInstance, Class<?> baseClass) { if (savedInstanceState == null) { return; } Class<?> clazz = classInstance.getClass(); while (baseClass.isAssignableFrom(clazz)) { String className = clazz.getName(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(SaveInstance.class)) { String key = className + "#" + field.getName(); field.setAccessible(true); try { Object fieldVal = savedInstanceState.get(key); if (fieldVal != null) { field.set(classInstance, fieldVal); } } catch (Throwable t) { Log.d(TAG, "The field '" + key + "' was not retrieved from the bundle"); } } } clazz = clazz.getSuperclass(); } } } 

    Ejemplo de uso:

     public class MainActivity extends Activity { @SaveInstance private String foo; @SaveInstance private int bar; @SaveInstance private Intent baz; @SaveInstance private boolean qux; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Icicle.load(savedInstanceState, this); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icicle.save(outState, this); } } 

    Nota: Este código fue adaptado de un proyecto de biblioteca llamado AndroidAutowire, que está licenciado bajo la licencia MIT .

    Meanwhile I do in general no more use

     Bundle savedInstanceState & Co 

    the live cycle is for most activities too complicated and not necessary. And google states itself, it is NOT even reliable.

    My way is to save any changes immediately in the preferences

      SharedPreferences p; p.edit().put(..).commit() 

    in some way SharedPreferences work similar like Bundles. And naturally and at first such values have to be red from preferences.

    In the case of complex data you may use Sqlite instead of using preferences.

    When applying this concept, the activity just continues to use the last saved state, regardless whether it was an initial open with reboots in between or a reopen due to the back stack.

    The onSaveInstanceState(bundle) and onRestoreInstanceState(bundle) methods are useful for data persistence merely while rotating the screen (orientation change).
    They are not even good while switching between applications (since the onSaveInstanceState() method is called but onCreate(bundle) and onRestoreInstanceState(bundle) is not invoked again.
    For more persistence use shared preferences. read this article

    To answer the original question directly. savedInstancestate is null because your Activity is never being re-created.

    Your Activity will only be re-created with a state bundle when:

    • Configuration changes such as changing the orientation or phone language which may requires a new activity instance to be created.
    • You return to the app from the background after the OS has destroyed the activity.

    Android will destroy background activities when under memory pressure or after they've been in the background for an extended period of time.

    When testing your hello world example there are a few ways to leave and return to the Activity.

    • When you press the back button the Activity is finished. Re-launching the app is a brand new instance. You aren't resuming from the background at all.
    • When you press the home button or use the task switcher the Activity will go into the background. When navigating back to the application onCreate will only be called if the Activity had to be destroyed.

    In most cases if you're just pressing home and then launching the app again the activity won't need to be re-created. It already exists in memory so onCreate() won't be called.

    There is an option under Settings -> Developer Options called "Don't keep activities". When it's enabled Android will always destroy activities and recreate them when they're backgrounded. This is a great option to leave enabled when developing because it simulates the worst case scenario. ( A low memory device recycling your activities all the time ).

    The other answers are valuable in that they teach you the correct ways to store state but I didn't feel they really answered WHY your code wasn't working in the way you expected.

    Recreating an Activity

    There are a few scenarios in which your activity is destroyed due to normal app behavior, such as when the user presses the Back button or your activity signals its own destruction by calling finish() . The system may also destroy your activity if it's currently stopped and hasn't been used in a long time or the foreground activity requires more resources so the system must shut down background processes to recover memory.

    When your activity is destroyed because the user presses Back or the activity finishes itself, the system's concept of that Activity instance is gone forever because the behavior indicates the activity is no longer needed. However, if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed . The saved data that the system uses to restore the previous state is called the "instance state" and is a collection of key-value pairs stored in a Bundle object.

    To save additional data about the activity state, you must override the onSaveInstanceState() callback method. The system calls this method when the user is leaving your activity and passes it the Bundle object that will be saved in the event that your activity is destroyed unexpectedly. If the system must recreate the activity instance later, it passes the same Bundle object to both the onRestoreInstanceState() and onCreate() methods. Introduzca aquí la descripción de la imagen

    As the system begins to stop your activity, it calls onSaveInstanceState() (1) so you can specify additional state data you'd like to save in case the Activity instance must be recreated. If the activity is destroyed and the same instance must be recreated, the system passes the state data defined at (1) to both the onCreate() method (2) and the onRestoreInstanceState() method (3).

    Save Your Activity State

    As your activity begins to stop, the system calls onSaveInstanceState() so your activity can save state information with a collection of key-value pairs. The default implementation of this method saves information about the state of the activity's view hierarchy, such as the text in an EditText widget or the scroll position of a ListView .

    To save additional state information for your activity, you must implement onSaveInstanceState() and add key-value pairs to the Bundle object. Por ejemplo:

      static final String STATE_SCORE = "playerScore"; static final String STATE_LEVEL = "playerLevel"; ... @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save the user's current game state savedInstanceState.putInt(STATE_SCORE, mCurrentScore); savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel); // Always call the superclass so it can save the view hierarchy state super.onSaveInstanceState(savedInstanceState); } 

    Caution: Always call the superclass implementation of onSaveInstanceState() so the default implementation can save the state of the view hierarchy.

    Restore Your Activity State

    When your activity is recreated after it was previously destroyed, you can recover your saved state from the Bundle that the system passes your activity. Both the onCreate() and onRestoreInstanceState() callback methods receive the same Bundle that contains the instance state information.

    Because the onCreate() method is called whether the system is creating a new instance of your activity or recreating a previous one, you must check whether the state Bundle is null before you attempt to read it. If it is null, then the system is creating a new instance of the activity, instead of restoring a previous one that was destroyed.

    For example, here's how you can restore some state data in onCreate() :

      @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Always call the superclass first // Check whether we're recreating a previously destroyed instance if (savedInstanceState != null) { // Restore value of members from saved state mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } else { // Probably initialize members with default values for a new instance } ... } 

    Instead of restoring the state during onCreate() you may choose to implement onRestoreInstanceState() , which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null:

      public void onRestoreInstanceState(Bundle savedInstanceState) { // Always call the superclass so it can restore the view hierarchy super.onRestoreInstanceState(savedInstanceState); // Restore state members from saved instance mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } 

    My problem was that I needed persistence only during the application lifetime (ie a single execution including starting other sub-activities within the same app and rotating the device etc). I tried various combinations of the above answers but did not get what I wanted in all situations. In the end what worked for me was to obtain a reference to the savedInstanceState during onCreate:

     mySavedInstanceState=savedInstanceState; 

    and use that to obtain the contents of my variable when I needed it, along the lines of:

     if (mySavedInstanceState !=null) { boolean myVariable = mySavedInstanceState.getBoolean("MyVariable"); } 

    I use onSaveInstanceState and onRestoreInstanceState as suggested above but I guess i could also or alternatively use my method to save the variable when it changes (eg using putBoolean )

    Although the accepted answer is correct, there is a faster and easier method to save the Activity state on Android using a library called Icepick . Icepick is an annotation processor that takes care of all the boilerplate code used in saving and restoring state for you.

    Doing something like this with Icepick:

     class MainActivity extends Activity { @State String username; // These will be automatically saved and restored @State String password; @State int age; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Icepick.restoreInstanceState(this, savedInstanceState); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } } 

    Is the same as doing this:

     class MainActivity extends Activity { String username; String password; int age; @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putString("MyString", username); savedInstanceState.putString("MyPassword", password); savedInstanceState.putInt("MyAge", age); /* remember you would need to actually initialize these variables before putting it in the Bundle */ } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); username = savedInstanceState.getString("MyString"); password = savedInstanceState.getString("MyPassword"); age = savedInstanceState.getInt("MyAge"); } } 

    Icepick will work with any object that saves its state with a Bundle .

    There are basically two ways to implement this change.

    1. using onSaveInstanceState() and onRestoreInstanceState() .
    2. In manifest android:configChanges="orientation|screenSize" .

    I really do not recommend to use second method. Since in one of my experience it was causing half of the device screen black while rotating from portrait to landscape and vice versa.

    Using first method mentioned above , we can persist data when orientation is changed or any config change happens. I know a way in which you can store any type of data inside savedInstance state object.

    Example: Consider a case if you want to persist Json object. create a model class with getters and setters .

     class MyModel extends Serializable{ JSONObject obj; setJsonObject(JsonObject obj) { this.obj=obj; } JSONObject getJsonObject() return this.obj; } } 

    Now in your activity in onCreate and onSaveInstanceState method do the following. It will look something like this:

     @override onCreate(Bundle savedInstaceState){ MyModel data= (MyModel)savedInstaceState.getSerializable("yourkey") JSONObject obj=data.getJsonObject(); //Here you have retained JSONObject and can use. } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); //Obj is some json object MyModel dataToSave= new MyModel(); dataToSave.setJsonObject(obj); oustate.putSerializable("yourkey",dataToSave); } 

    When an activity is created it's onCreate() method is called.

      @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } 

    savedInstanceState is an object of Bundle class which is null for the first time, but it contains values when it is recreated. To save Activity's state you have to override onSaveInstanceState().

      @Override protected void onSaveInstanceState(Bundle outState) { outState.putString("key","Welcome Back") super.onSaveInstanceState(outState); //save state } 

    put your values in "outState" Bundle object like outState.putString("key","Welcome Back") and save by calling super. When activity will be destroyed it's state get saved in Bundle object and can be restored after recreation in onCreate() or onRestoreInstanceState(). Bundle received in onCreate() and onRestoreInstanceState() are same.

      @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //restore activity's state if(savedInstanceState!=null){ String reStoredString=savedInstanceState.getString("key"); } } 

    o

      //restores activity's saved state @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { String restoredMessage=savedInstanceState.getString("key"); } 

    Not sure if my solution is frowned upon or not but I use a bound service to persist ViewModel state. Whether you store it in memory in the service or persist and retrieve from a SqlLite database depends on your requirements. This is what services of any flavor do, they provide services such as maintaining application state and abstract common business logic.

    Because of memory and processing constraints inherent on mobile devices, I treat Android views in a similar way to a web page. The page does not maintain state, it is purely a presentation layer component whose only purpose is to present application state and accept user input. Recent trends in web app architecture employ the use of the age old Model, View, Controller (MVC) pattern, where the page is the View, Domain data is the model and the controller sits behind a web service. The same pattern can be employed in android with the View being well … the View, the model is your domain data and the Controller is implemented as an Android bound service. Whenever you want a view to interact with the controller, bind to it on start/resume and unbind on stop/pause.

    This approach gives you the added bonus of enforcing the Separation of Concern design principle in that all of you application business logic can be moved into your service which reduces duplicated logic across multiple views and allows the view to enforce another important design principle, Single Responsibility.

    Simple quick to solve this problem is using IcePick

    First, setup the library in app/build.gradle

     repositories { maven {url "https://clojars.org/repo/"} } dependencies { compile 'frankiesardo:icepick:3.2.0' provided 'frankiesardo:icepick-processor:3.2.0' } 

    Now, let's check this example below how to save state in Activity

     public class ExampleActivity extends Activity { @State String username; // This will be automatically saved and restored @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Icepick.restoreInstanceState(this, savedInstanceState); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } } 

    It works for Activities, Fragments or any object that needs to serialize its state on a Bundle (eg mortar's ViewPresenters)

    Icepick can also generate the instance state code for custom Views:

     class CustomView extends View { @State int selectedPosition; // This will be automatically saved and restored @Override public Parcelable onSaveInstanceState() { return Icepick.saveInstanceState(this, super.onSaveInstanceState()); } @Override public void onRestoreInstanceState(Parcelable state) { super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state)); } // You can put the calls to Icepick into a BaseCustomView and inherit from it // All Views extending this CustomView automatically have state saved/restored } 

    To get activity state data stored in onCreate(), first you have to save data in savedInstanceState by overrding SaveInstanceState(Bundle savedInstanceState) method.

    When activity destroy SaveInstanceState(Bundle savedInstanceState) method gets called and there you save data you want to save. And you get same in onCreate() when activity restart.(savedInstanceState wont be null since you have saved some data in it before activity get destroyed)

    Here is a comment from Steve Moseley 's answer (by ToolmakerSteve ) that puts things into perspective (in the whole onSaveInstanceState vs onPause, east cost vs west cost saga)

    @VVK – I partially disagree. Some ways of exiting an app don't trigger onSaveInstanceState (oSIS). This limits the usefulness of oSIS. Its worth supporting, for minimal OS resources, but if an app wants to return the user to the state they were in, no matter how the app was exited, it is necessary to use a persistent storage approach instead. I use onCreate to check for bundle, and if it is missing, then check persistent storage. This centralizes the decision making. I can recover from a crash, or back button exit or custom menu item Exit, or get back to screen user was on many days later. – ToolmakerSteve Sep 19 '15 at 10:38

    You need to override onSaveInstanceState(Bundle savedInstanceState) and write the application state values you want to change to the Bundle parameter like this:

     @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // Save UI state changes to the savedInstanceState. // This bundle will be passed to onCreate if the process is // killed and restarted. savedInstanceState.putBoolean("MyBoolean", true); savedInstanceState.putDouble("myDouble", 1.9); savedInstanceState.putInt("MyInt", 1); savedInstanceState.putString("MyString", "Welcome back to Android"); // etc. } 

    The Bundle is essentially a way of storing a NVP ("Name-Value Pair") map, and it will get passed in to onCreate() and also onRestoreInstanceState() where you'd extract the values like this:

     @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // Restore UI state from the savedInstanceState. // This bundle has also been passed to onCreate. boolean myBoolean = savedInstanceState.getBoolean("MyBoolean"); double myDouble = savedInstanceState.getDouble("myDouble"); int myInt = savedInstanceState.getInt("MyInt"); String myString = savedInstanceState.getString("MyString"); } 

    You would usually use this technique to store instance values for your application (selections, unsaved text, etc.).

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.