6

Después de pasar por un libro introductorio de programación de Android, quería modificar la aplicación de ejemplo para solidificar mi comprensión de algunos temas que realmente no estaban cubiertos. Al hacer el cambio, cometí un error, pero tengo curiosidad por saber por qué el error funcionó en algunos casos, pero no en otros.¿Por qué a veces funciona el guardar una Hashtable de objetos no Parcelable en onSaveInstanceState()?

Una actividad dentro de la aplicación almacena una serie de preguntas en un Hashtable<Integer, Question>, donde Question es una clase pequeña que contiene un int y dos cadenas. Como se escribió originalmente, la actividad descarga las preguntas de un servidor en cada onCreate(), por lo que quería implementar onSaveInstanceState() para evitar algunas descargas redundantes. onSaveInstanceState() guarda el Hashtable en el paquete usando putSerializable().

@Override 
protected void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
      // mQuestions is a member variable of 
      // type Hashtable<Integer, Question> 
    if (mQuestions != null && mQuestions.size() > 0) { 
     outState.putSerializable(SAVED_QUESTIONS, mQuestions); 
    } 
} 

Funcionó perfectamente para los cambios de orientación de la pantalla incluso antes de saber qué era una Parcelable o cómo implementarla. Solo sabía que había un problema cuando presioné la tecla de inicio del emulador y la aplicación silenciosamente, se bloqueó de manera invisible sin salida de LogCat. El seguimiento de la pila me llevó a buscar Parcelable y hacer que Question lo implemente.

Mi pregunta no es qué hice mal. La pregunta es la siguiente: Cuando la clase Question no implementó Parcelable, ¿por qué la aplicación se bloqueó solo al presionar Inicio y no en la orientación de la pantalla cambiar?

+0

"onSaveInstanceState() guarda la tabla hash en el paquete usando putSerializable()". - No coloque su modelo de datos en estado de instancia. Pon tu modelo de datos en un archivo o una base de datos. Así es como "previene descargas redundantes". "Solo sabía que había un problema cuando presioné la tecla de inicio del emulador y la aplicación silenciosamente, se bloqueó de manera invisible sin salida de LogCat". - y tu prueba de este choque silencioso e invisible es ... ¿qué, exactamente? – CommonsWare

+0

@CommonsWare: apareció una ventana emergente en Eclipse que solicitaba abrir la perspectiva Debug porque el lanzamiento se había suspendido. Así es como supe que se estrelló. He comentado el código para hacer la pregunta parcelable, y en un intento (de varios), se forzó a cerrar con los errores registrados, pero eso no sucedió antes de publicar esta pregunta. – erichamion

+0

Sí, los datos realmente deberían guardarse en un archivo, pero eso no es lo que estaba tratando de hacer. No estoy trabajando en una aplicación de producción (incluso para uso personal, hobby). Estaba modificando la aplicación de demostración creada a través del desarrollo de la aplicación Teach Yourself para Android de _Sam en el libro de 24 horas_. Incluso para un libro introductorio, parece dejar de lado algunos temas muy básicos. Quería ver cómo funciona onSaveInstanceState(). Creo que ahora tengo los mecanismos para ello, sino cuándo y cómo usarlo. – erichamion

Respuesta

1

Citando Steve Moseley

en cuenta que es NO seguro de usar y onSaveInstanceStateonRestoreInstanceState, de acuerdo con la documentación sobre los estados de actividad en http://developer.android.com/reference/android/app/Activity.html.

El documento (en la sección 'Actividad del ciclo de vida'):

en cuenta que es importante ahorrar datos persistentes en onPause() lugar de onSaveInstanceState(Bundle) debido a que la tarde no es parte de la ciclo de vida devoluciones de llamada, por lo que no será llamado en cada situación como se describe en su documentación.

En otras palabras, poner su guardar/restaurar código en onPause() y onResume() lugar!

+0

Esto sería más apropiado como un comentario sobre la pregunta original, ya que no es una respuesta a la pregunta tal como se publicó: "... ¿por qué la aplicación se bloqueó solo presionando Inicio y no en un cambio de orientación de pantalla?" – glorifiedHacker

2

Por lo que tengo entendido, Android no serializa un estado de instancia al volver a crear una actividad después de cambios en la configuración. Es por eso que tu código funciona. Los objetos persistentes simplemente no necesitan ser empacados porque existen solo en la memoria.

Esto parece una optimización. Android sabe que el proceso no finalizará en este caso y no es necesario guardar el estado de la instancia en un archivo. (En teoría, el proceso puede finalizar durante el cambio de configuración y realmente no sé cómo Android resuelve este problema).

Pero cuando el usuario presiona la tecla de inicio su aplicación se convierte en fondo. Y su proceso puede finalizar en caso de poca memoria. Android necesita guardar el estado de la actividad en un archivo para poder restaurar su aplicación y sus actividades en el futuro. En este caso, el estado de la instancia realmente se serializa y se guarda en un almacenamiento persistente.Y es por eso que tu código no funciona.

La terminación del proceso puede ocurrir en cualquier momento, por lo que no puede confiar en algunos detalles de implementación. Simplemente haga que el estado de la instancia sea parcelable o serializable y no volverá a enfrentar este problema.

+0

Aunque no lo he confirmado yo mismo, esta respuesta tiene sentido para mí (por qué serializar algo para un cambio de configuración cuando las variables aún persisten en la memoria). También es la única respuesta hasta el momento que intenta abordar la pregunta original publicada por erichamion. Por lo tanto estoy otorgando la recompensa a esta respuesta. – glorifiedHacker

0

La aplicación no se colgó. Simplemente se cerró cuando el usuario hizo clic en la tecla de inicio. Es por eso que no hubo salida para LogCat.

Establezca un punto de interrupción en Activity.onDestroy() para confirmar esto. Si tengo razón en Destroy() se llamará pero onSaveInstanceState() no, porque onSaveInstanceState() solo se invoca cuando la aplicación se coloca en el estado de fondo, no cuando se apaga.

Si necesita guardar el estado de la aplicación cuando se apaga, colocar el código en OnDestroy() y guardarlo en algo más persistente que un paquete.

Barry

Cuestiones relacionadas