La base de datos SQLite de Android se corrompe

Este enlace describe mi problema exactamente: http://old.nabble.com/Android-database-corruption-td28044218.html#a28044218

Hay alrededor de 300 personas que utilizan mi aplicación para Android en este momento y de vez en cuando obtengo un informe de fallo en el servidor con este seguimiento de pila:

android.database.sqlite.SQLiteDatabaseCorruptException: database disk image is malformed at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2596) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621) at android.app.ActivityThread.access$2200(ActivityThread.java:126) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:4595) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) at dalvik.system.NativeStart.main(Native Method) Caused by: android.database.sqlite.SQLiteDatabaseCorruptException: database disk image is malformed at android.database.sqlite.SQLiteQuery.native_fill_window(Native Method) at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:75) at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:295) at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:276) at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:171) at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:248) 

El resultado es la caída de la aplicación y la pérdida de todos los datos de la base de datos.

Una cosa a tener en cuenta es que cada vez que leo o escribo en la base de datos recibo una nueva SQLiteDatabase y la cierro tan pronto como termine. Hice esto en un intento de prevenir este tipo de errores de corrupción.

También intenté sincronizar todas las lecturas y escrituras del DB usando un solo objeto estático y eso no parecía ayudar.

¿Es posible que esto sea solo un error de SQLite?

Encontré un error similar con la aplicación de correo electrónico incorporada aquí: http://code.google.com/p/android/issues/detail?id=5610 .

Aquí está mi código:

 public class KeyValueTableAdapter extends BaseTableAdapter { private String tableName; private String keyColumnName; private String valueColumnName; public KeyValueTableAdapter(Context context, String tableName, String keyColumnName, String valueColumnName) { super(context); this.tableName = tableName; this.keyColumnName = keyColumnName; this.valueColumnName = valueColumnName; } protected String getStringValue(int key) { Cursor cursor = null; SQLiteDatabase db = null; String value; try { db = dbOpenHelper.getReadableDatabase(); cursor = db.query(true, tableName, new String[] { valueColumnName }, keyColumnName + "=" + key, null, null, null, null, null); if ((cursor.getCount() == 0) || !cursor.moveToFirst()) { value = null; } else { value = cursor.getString(0); } } finally { if (cursor != null) cursor.close(); if (db != null) db.close(); dbOpenHelper.close(); } return value; } } public abstract class BaseTableAdapter { protected DbOpenHelper dbOpenHelper; public BaseTableAdapter(Context context) { this.dbOpenHelper = new DbOpenHelper(context, DatabaseSettings.DATABASE_NAME, null, DatabaseSettings.DATABASE_VERSION); } } 

"El DB mantiene la información de sesión por lo que no es muy factible hacer una copia de seguridad.Los datos cambian por minuto"

Debe intentar usar SharedPreferences: almacena pares clave-valor (en el fondo, utiliza un archivo). Almacenamiento de valores:

 SharedPreferences sp=MyActivity.getSharedPreferences("Name", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.putString("key", value); editor.putBoolean("another", true); editor.commit(); 

Recuperando datos:

 sp.getString("key", "Not found"); // "Not found" is the default value // if sp does not contain the specified key sp.getBoolean("another", false); // false is the default value // if sp does not contain the specified key 

Vea getSharedPreferences y SharedPreferences para una descripción más detallada.

Lo más probable es que el proceso de la base de datos se esté matando durante una E / S. Por ejemplo, por un asesino de tareas, o si está permitiendo que las operaciones de escritura de db continúen durante un tiempo cuando la aplicación debe apagar o dormir …

Vea si puede reproducir el problema poniendo su aplicación en un bucle de escritura de DB y usando un asesino de tareas en él.

Escenario: 32 bytes que se escriben en la base de datos, la tarea de escritor se pierde después de sólo escribir 10, resultado: base de datos izquierda en estado inconsistente y posiblemente corrupto.

Véase también: Android proceso asesino

EDIT: abrir y cerrar el DB para cada lectura / escritura? ¡Para! 🙂

El uso de varias instancias de SQLiteDatabase podría estar causando el problema si tiene dos instancias que actualizan el mismo archivo de base de datos al mismo tiempo.

Implementar un proceso de backup db cada día, y si el DB se corrompe basta con reemplazar la base de datos con una copia de seguridad. Puede utilizar métodos simples de copia de copia de archivos para mantener una copia de seguridad cada día.

Ya que no puedo comentar -yet- en el post de Brad.

Tengo que estar de acuerdo con la sobrecarga adicional.

Tengo un HTC Magic como mi teléfono diario, y el carnero siempre es un problema.

Los teléfonos con Android están en extremos muy diferentes del $$$

Algunos son super baratos y algunos son muy caros, esto básicamente se reduce a la RAM, y la CPU.

Las personas que ejecutan asesinos de tareas arruinan sus teléfonos Android.

Como desarrollador, debe sugerir a la gente que no los use, o simplemente negar el apoyo a las personas que utilizan asesinos de tareas, ya que android no necesita estas "mejoras" (pregunte a steve (cianógeno))

También la new declaración en android es muy costosa.

Desea limitar la cantidad de llamadas new al programar para android.

La programación para android es todo sobre la reutilización de la memoria preciosa. (HTC Magics / Dreams sólo tiene 96 MB disponibles para las aplicaciones, y la mayor parte ya está en uso)

En cuanto a su SQLiteDB … la API dice que su SQLiteDB es privado para su aplicación.

No veo por qué necesita abrir y cerrar una conexión NUEVA cada vez que quiera leer o escribir en ella.

Prefiero mantener la conexión abierta hasta que el usuario pierda el foco de ella.

Sin embargo, si está escribiendo un proveedor de contenido, esa es una historia diferente.

  • SQLite de Android: Actualización
  • ¿Cursor.getString () coacciona un int en una cadena?
  • Sqlite no devuelve ninguna tabla, pero la tabla está presente cuando se obtiene en el dispositivo OnePlusTwo
  • Buscar en toda la base de datos SQLite utilizando FTS3 / FTS4?
  • Android - Código de error 11 al importar la base de datos Sqlite en Galaxy Note
  • Android: La ventana del cursor está llena
  • Obtención de una excepción SQLiteCantOpenDatabaseException
  • Android Guardar objeto como blob en sqlite
  • La columna _id no existe
  • SQLite y almacenamiento de imágenes
  • Ejemplo de búsqueda de texto completo en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.