Problemas con "onSaveInstanceState" y "onRestoreInstanceState"

130 views
Skip to first unread message

David Ruiz Urraca

unread,
Oct 8, 2014, 2:33:16 PM10/8/14
to desarrollad...@googlegroups.com
Buenas tardes.

Tengo una aplicación con 3 activity's y una base de datos sqlite con un formato maestro-detalle-subdetalle.

En la primera activity, hago una consulta a la base de datos y muestro en un listview los resultados. Cuando el usuario, pulsa uno de los registros del listview, lanzo la segunda activity pasándole el registro que ha seleccionado, en un bundle y ahí se muestra de forma mucho más detallada la información. Una vez en esta segunda activity, existe una opción en la ActionBar para poder ver información extra relacionada, para lo que se abre una tercera activity, donde paso otro bundle con los parámetros.
Hasta aquí todo funciona perfectamente.

El problema viene cuando intento volver de esta tercera activity a la segunda, puesto que esta segunda activity está esperando el bundle de la primera, pero al volver de la tercera, no lo recibe y me da una "NullPointerException".
Si vuelvo con el botón "Back" del sistema, todo funciona perfectamente, sin embargo si vuelvo con el botón "UP" (se añade automáticamente al indicar en el Manifest cual es la activity padre) es cuando me salta este error.

Para intentar evitar esto, estoy intentado utilizar los métodos "onSaveInstanceState" y "onRestoreInstanceState" pero creo que o los estoy utilizando mal, o no sirven para esto que me propongo.

Gracias de antemano.

Gabriel Pozo

unread,
Oct 8, 2014, 3:11:18 PM10/8/14
to desarrollad...@googlegroups.com
logcat, código? ;)
Normas

--
Para participar es necesario que leas detenidamente las normas del grupo: http://goo.gl/8h8ez2
---
Has recibido este mensaje porque estás suscrito al grupo "desarrolladores-android" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a desarrolladores-a...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a desarrollad...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/desarrolladores-android.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/desarrolladores-android/338d7b6d-4a2f-4fe7-a2ea-35c7e9821cd4%40googlegroups.com.
Para acceder a más opciones, visita https://groups.google.com/d/optout.

David Ruiz Urraca

unread,
Oct 8, 2014, 3:42:33 PM10/8/14
to desarrollad...@googlegroups.com
Tienes razón, no quería meter código por no meter mucha morralla, por si con la explicación era suficiente, pero aquí va el código (he quitado código no relevante para el problema)
Lo único que faltaría es poner el Manifest en el que indico en la activity "HistoryActivity" que su parentActivityName es "ExerciseView"

LOGCAT

10-08 21:33:54.532: W/dalvikvm(2102): threadid=1: thread exiting with uncaught exception (group=0x417c9700)
10-08 21:33:54.540: E/AndroidRuntime(2102): FATAL EXCEPTION: main
10-08 21:33:54.540: E/AndroidRuntime(2102): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.user.app_demo/com.user.app_demo.ExerciseView}: java.lang.NullPointerException
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.access$600(ActivityThread.java:141)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.os.Handler.dispatchMessage(Handler.java:99)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.os.Looper.loop(Looper.java:137)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.main(ActivityThread.java:5103)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at java.lang.reflect.Method.invokeNative(Native Method)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at java.lang.reflect.Method.invoke(Method.java:525)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at dalvik.system.NativeStart.main(Native Method)
10-08 21:33:54.540: E/AndroidRuntime(2102): Caused by: java.lang.NullPointerException
10-08 21:33:54.540: E/AndroidRuntime(2102):  at com.user.app_demo.Converter.bundleToMaximum(Converter.java:18)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at com.user.app_demo.ExerciseView.onStart(ExerciseView.java:54)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.Activity.performStart(Activity.java:5143)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
10-08 21:33:54.540: E/AndroidRuntime(2102):  ... 11 more



--------------------------


ACTIVITY 1 (MainActivity.java)

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myList = (ListView) findViewById(R.id.listLastMaximums);
myList.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> list, View view,
int position, long id) {
Intent intent = new Intent(MainActivity.this,
ExerciseView.class);
Bundle b = new Bundle();
b = Converter.maximumToBundle(listLastMaximums.get(position));
intent.putExtras(b);
startActivity(intent);
}
});
}


--------------------------


ACTIVITY 2 (ExerciseView.java)

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.exercise_view);
bundle = this.getIntent().getExtras();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState = Converter.maximumToBundle(maximum);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
bundle = savedInstanceState;
}
@Override
protected void onStart() {
super.onStart();
maximum = Converter.bundleToMaximum(bundle);
...
...
...
}
private void history_maximums() {
Intent intent = new Intent(ExerciseView.this, HistoryActivity.class);
Bundle b = new Bundle();
b.putString(Values.getExerciseid(), maximum.getExercise_id());
intent.putExtras(b);
startActivity(intent);
}


--------------------------


ACTIVITY 3 (HistoryActivity.java)

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.history);
Bundle b = this.getIntent().getExtras();
id_exercise = b.getString("exercise_id");

listHistory = (ListView) findViewById(R.id.listAllMaximums);
}
@Override
protected void onStart() {
super.onStart();
populateList();
}

Has recibido este mensaje porque estás suscrito a un tema del grupo "desarrolladores-android" de Grupos de Google.
Para anular la suscripción a este tema, visita https://groups.google.com/d/topic/desarrolladores-android/TI7g8W8hoUM/unsubscribe.
Para anular la suscripción a este grupo y a todos sus temas, envía un correo electrónico a desarrolladores-a...@googlegroups.com.

Para publicar en este grupo, envía un correo electrónico a desarrollad...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/desarrolladores-android.

Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
David Ruiz Urraca
        

Alejandro Vaquero

unread,
Oct 8, 2014, 4:40:27 PM10/8/14
to
Al parecer, aunque a simple vista el botón "UP" de la Action Bar y el botón Back tengan un comportamiento idéntico, internamente actúan de forma distinta.

El botón Back termina la activity actual ( finish() ) y vuelve al estado anterior de la aplicación. Esto provoca la ejecución del método onResume() en la segunda actividad.

El botón Up, por su parte, indica a la app que la próxima actividad a cargar será la que tenemos establecida como "PARENT". Esto no significa que volvamos al estado anterior, sino que crea de nuevo la actividad. Por lo tanto, se ejecuta de nuevo el método onCreate(). Aquí es donde reside el problema, puesto que onCreate() intenta obtener el Bundle de nuevo, que no existe (de ahí la NullPointerException).

La solución más rápida sería hacer que el botón "Up" se comporte exactamente igual que Back. Por lo tanto, en la tercera activity:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch(item.getItemId()) {
        case android.R.id.home:
            onBackPressed(); // finish();
            return true;
    }
    return super.onOptionsItemSelected(item);
}
android.R.id.home es el valor para el botón Up. Sobrescribimos su implementación para que ejecute onBackPressed(), que es el comportamiento deseado. onBackPressed() simplemente realiza un finish(), así que puedes sustituirlo por ello si no tienes el método sobrescrito.


Tuve que lidiar con una situación similar hace un tiempo, pero en mi caso simplemente bastaba con recoger los valores en onResume() en lugar de en onCreate(). La información en lugar de un Bundle venía del almacenamiento interno, pero al volver atrás no se recargaba (al usar el botón Back no se ejecutaba onCreate() ).

Juan de Dios Maldonado Sánchez

unread,
Oct 9, 2014, 3:22:57 AM10/9/14
to desarrollad...@googlegroups.com
Observa que el error lo tienes aquí:

LOGCAT

10-08 21:33:54.532: W/dalvikvm(2102): threadid=1: thread exiting with uncaught exception (group=0x417c9700)
10-08 21:33:54.540: E/AndroidRuntime(2102): FATAL EXCEPTION: main
10-08 21:33:54.540: E/AndroidRuntime(2102): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.user.app_demo/com.user.app_demo.ExerciseView}: java.lang.NullPointerException
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.access$600(ActivityThread.java:141)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.os.Handler.dispatchMessage(Handler.java:99)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.os.Looper.loop(Looper.java:137)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.main(ActivityThread.java:5103)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at java.lang.reflect.Method.invokeNative(Native Method)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at java.lang.reflect.Method.invoke(Method.java:525)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at dalvik.system.NativeStart.main(Native Method)
10-08 21:33:54.540: E/AndroidRuntime(2102): Caused by: java.lang.NullPointerException
10-08 21:33:54.540: E/AndroidRuntime(2102):  at com.user.app_demo.Converter.bundleToMaximum(Converter.java:18)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at com.user.app_demo.ExerciseView.onStart(ExerciseView.java:54)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.Activity.performStart(Activity.java:5143)
10-08 21:33:54.540: E/AndroidRuntime(2102):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
10-08 21:33:54.540: E/AndroidRuntime(2102):  ... 11 more

Archivo Converter.java, línea 18. Es un NullPointerException, así que es bastante trivial solucionarlo si sabes programar en Java. 

David Ruiz Urraca

unread,
Oct 9, 2014, 7:21:35 AM10/9/14
to desarrollad...@googlegroups.com
Muchísimas gracias Alejandro, efectivamente era ese el problema.
No conocía bien la diferencia y el funcionamiento de esos botones.

Gracias de nuevo.

El 8 de octubre de 2014, 22:40, Alejandro Vaquero <ava...@gmail.com> escribió:
Al parecer, aunque a simple vista el botón "UP" de la Action Bar y el botón Back tengan un comportamiento idéntico, internamente actúan de forma distinta.

El botón Back termina la activity actual ( finish() ) y vuelve al estado anterior de la aplicación. Esto provoca la ejecución del método onResume().

El botón Up, por su parte, indica a la app que la próxima actividad a cargar será la que tenemos establecida como "PARENT". Esto no significa que volvamos al estado anterior, sino que crea de nuevo la actividad. Por lo tanto, se ejecuta de nuevo el método onCreate(). Aquí es donde reside el problema.

La solución más rápida sería hacer que el botón "Up" se comporte exactamente igual que Back. Por lo tanto, en la tercera activity:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch(item.getItemId()) {
        case android.R.id.home:
            onBackPressed(); // finish();
            return true;
    }
    return super.onOptionsItemSelected(item);
}
android.R.id.home es el valor para el botón Up. Sobrescribimos su implementación para que ejecute onBackPressed(), que es el comportamiento deseado. onBackPressed() simplemente realiza un finish(), así que puedes sustituirlo por ello si no tienes el método sobrescrito.


Tuve que lidiar con una situación similar hace un tiempo, pero en mi caso simplemente bastaba con recoger los valores en onResume() en lugar de en onCreate(). La información en lugar de un Bundle venía del almacenamiento interno, pero al volver atrás no se recargaba (al usar el botón Back no se ejecutaba onCreate() ).

--
Para participar es necesario que leas detenidamente las normas del grupo: http://goo.gl/8h8ez2
---
Has recibido este mensaje porque estás suscrito a un tema del grupo "desarrolladores-android" de Grupos de Google.
Para anular la suscripción a este tema, visita https://groups.google.com/d/topic/desarrolladores-android/TI7g8W8hoUM/unsubscribe.
Para anular la suscripción a este grupo y a todos sus temas, envía un correo electrónico a desarrolladores-a...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a desarrollad...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/desarrolladores-android.

Para acceder a más opciones, visita https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages