2012-04-20 11 views
14

Me pregunto qué estrategias usan otros para evitar la pérdida de datos al guardar archivos en Android. Tengo un par de aplicaciones de juegos que, en esencia, pueden guardar el estado del juego/guardar juego cada vez que el usuario hace una pausa (onPause).¿Evita la pérdida de datos debido a la interrupción al guardar archivos en android?

Esto funciona en el 99,99% de los casos, pero de vez en cuando recibo un ejemplo de un juego guardado donde el proceso de guardado ha sido incorrecto. Por lo general, este es un archivo XML mal formado, normalmente truncado en algún punto arbitrario. Basado en los informes de errores que recibo, creo que el problema ocurre principalmente cuando el usuario es interrumpido durante el juego por una llamada telefónica o algo así y el sistema operativo Android mata la aplicación antes de que pueda terminar de guardar. El código para guardar los archivos es bastante simple, así que tengo dificultades para ver qué más podría causar este problema.

Esto es un problema grave, ya que generalmente se arruinará el progreso de guardado del jugador.

Estaba pensando en escribir primero en un archivo vacío y luego copiarlo al archivo "real" solo después, pero sospecho que eso simplemente aumentaría el problema, ya que en general tomará más tiempo y aún corre el riesgo de ser interrumpido.

¿Alguien que tiene una manera segura de hacer esto que Android está relativamente garantizado para no ensuciar?


Así resumida, las opciones sugeridas hasta ahora (como yo las entiendo):

  1. utilizar un servicio para el proceso de guardado, en el supuesto de que esto va a ser menos propensos a ser asesinados por el OS.
  2. Guardar en archivo temporal; copiar cuando se haya guardado.
  3. Ahorro incremental del estado del juego (de hecho, ya lo uso para la información de registro del jugador).
  4. Combinación de 2 & 3.
  5. Mueva el guardado a otro subproceso, ya que el problema puede ser con ANR elimina [los comentarios de DC a continuación].

No creo que las Preferencias Compartidas funcionen para este tipo de datos estructurados. Por el momento, ninguno de estos métodos parece una solución ideal, por lo que todavía estoy abierto a sugerencias.


todavía no las he arreglado para poner a prueba todos estos enfoques, por lo que en lugar de perder la recompensa, he asignado a la respuesta que me siento que sería más probable para resolver el problema. Sin embargo, planeo revisar las diversas opciones antes de aceptar una respuesta. Gracias por todas las buenas sugerencias.

+0

demasiados datos para ser guardados en 'SharedPreference'? – Ronnie

+0

Sí - alrededor de 20K de datos en XML. Es posible que no sea un problema importante (no lo haya intentado), pero creo que la compleja estructura de los datos sería. –

+0

¿Cómo está guardando el estado del juego en 'onPause()'? ¿Estás haciendo E/S en el hilo principal (UI)? ¿Dónde está guardando el estado del juego (en la tarjeta SD u otra ubicación)? –

Respuesta

2

Creo que el ahorro de pequeñas porciones de datos (no todo el estado del juego) a la base de datos cada vez que el usuario realiza una acción (no sólo cuando onPause() se llama) sería el mejor enfoque en este caso. Sin embargo, esto puede requerir muchas modificaciones al código.

El compromiso sería dividir el estado del juego en porciones más pequeñas o sub-estados (digamos, round1, round2, ..., players, etc.) y de nuevo almacenar datos en archivos apropiados como el usuario realiza cualquier acción, no esperando la llamada onPause(). Esto reduciría significativamente la probabilidad de pérdida y al menos garantizaría que el usuario no pierda todo el progreso del juego. Además, para evitar estados incoherentes de su aplicación, que pueden aparecer cuando se interrumpe el proceso de guardado, será mejor que guarde los datos primero en el archivo temporal y solo en caso de éxito simplemente cambie el nombre del archivo, no copie su contenido (digamos, round1.xml.tmp cambiar el nombre a round1.xml).

4

Esto suena como un buen trabajo para un servicio.

http://developer.android.com/reference/android/app/Service.html

+0

Según tengo entendido, un Servicio también puede ser forzado a morir, y está conectado al proceso que lo inició. No estoy seguro de que esto ayude mucho, en ese caso, ya que el problema parece ser causado por el sistema operativo Android que mata la aplicación. –

+0

Un servicio se ejecuta en segundo plano, el sistema operativo definitivamente estará matando a su aplicación. Tal vez deberías considerar esta sugerencia ... – Kickaha

+0

El SO puede matar cualquier cosa, sin embargo, sigo creyendo que un servicio es lo que quieres usar. –

0

Si es posible, usa SharedPreferences para almacenar el estado de tu juego. Sus cambios serán cometidos solo después de llamar al commit(). Puede hacer el guardado en la devolución de llamada onSaveInstanceState. Lee el docs here.

0

Primero, trataría de ver si la aplicación realmente se elimina sin notificación porque no creo que sea así. Las aplicaciones pueden ser detenidas por algo así como una llamada telefónica, pero realmente no creo que Android lo esté acabando sin ninguna notificación. Podría decidir finalizarlo, pero no sin guardar el estado, etc.

Quizás solo haya un error al guardarlo.

Una forma que no requiere mucha modificación para comprobar que sería usar una suma de comprobación o usar de alguna otra manera para verificar la integridad de los datos guardados (tamaño, marcador final, etc.). Todo lo que tiene que hacer es guardarlo, leerlo y verificarlo (registrar cualquier error) y repetirlo hasta que sea correcto. Puede que no sea tan bueno si guarda grandes cantidades de datos, pero para los simples gamedatos debería estar bien.

También puede establecer un estado cuando la aplicación se inicia y finaliza, y luego sabría en el próximo inicio si finalizó correctamente la última vez o no y si tiene que tomar medidas adicionales.

+0

Es difícil estar seguro, ya que no puedo recrear la situación yo mismo. Pero todos los informes confirmados que he recibido con este tipo de problema suelen ser casos en los que el usuario ha sido interrumpido por una llamada telefónica o algo similar. –

+0

Estoy bastante seguro de que no hay ningún error con el propio ahorro; la API XML no debería poder escribir archivos truncados de este tipo en circunstancias normales. –

3

Hemos tenido problemas ocasionales cuando estamos haciendo I/O (generalmente escribiendo) para el almacenamiento persistente (sistema de archivos privado en la memoria interna) desde el hilo principal. Usualmente esto no toma mucho tiempo en absoluto, pero ocasionalmente toma inexplicablemente años (20 o 30 segundos o más). Parece que las implementaciones del sistema de archivos de Android en algunos dispositivos no admiten el acceso concurrente (ver this, por lo que su E/S puede bloquear si otro proceso está usando el sistema de archivos. Si está haciendo su E/S en el hilo principal, el sistema operativo puede/matará su actividad si bloquea durante demasiado tiempo. Esto puede ser lo que le está sucediendo.

Debido a este problema, le sugiero que mueva todas sus E/S a un hilo separado (no el principal hilo). Así que, por ejemplo, para guardar el estado del juego, en OnPause() llama a un método que serializa el estado del juego a un ByteArrayOutputStream que luego transfieres a un hilo separado para escribirlo finalmente en el sistema de archivos.

+0

Esto suena bastante interesante; ciertamente algo que necesitaré investigar. –

Cuestiones relacionadas