2010-05-05 32 views
8

Este enlace describe mi problema exactamente: http://old.nabble.com/Android-database-corruption-td28044218.html#a28044218base de datos de Android SQLite se corrompe

hay cerca de 300 personas que utilizan mi aplicación Android en este momento y cada vez y mientras consigo un informe de bloqueo al servidor con este seguimiento de la 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 falla de la aplicación y la pérdida de todos los datos en la base de datos.

Una cosa a tener en cuenta es que cada vez que leo o escribo en la base de datos obtengo una nueva base de datos SQLite y la cierro tan pronto como haya terminado. Hice esto para intentar evitar este tipo de errores de corrupción.

También intenté sincronizar todas las lecturas y escrituras de bases de datos con un solo objeto estático y eso no pareció 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); 
    } 

} 
+0

¿Utiliza triggers en su base de datos? – Pentium10

+0

No, esta tabla en particular es solo una "tabla de clave/valor". Dos columnas: una clave principal (entero) y otra no nula (texto). ¿Crees que usar el texto podría ser el problema? Estoy un poco familiarizado con la escritura de SQLite. –

+0

SQLite no tiene forma, eso no cuenta. Puede insertar texto en un campo de fecha :) – Pentium10

Respuesta

-3

"la base de datos contiene información de sesión, por lo no es muy factible hacer una copia de seguridad Los cambios de datos por el momento."

debería intentar usar SharedPreferences: almacena pares de valores clave (en el fondo, usa un archivo). valores de almacenamiento:

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

recuperación de 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 

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

+4

El problema está relacionado con la base de datos y, por lo tanto, una solución para usar las preferencias compartidas no es una solución. – slott

+0

El problema está relacionado con la base de datos y, por lo tanto, no usar una base de datos puede ser una solución, especialmente cuando se basa en los comentarios de Brandon, ni siquiera es la mejor manera de almacenar sus datos (pequeños pares clave-valor que cambian frecuentemente). –

+1

El punto aquí es resolver el problema y no solucionarlo. Por lo general, las soluciones tienen una forma de vengarse de usted. – slott

2

Usando varias instancias de SQLiteDatabase podría ser la causa de su problema si tiene dos instancias de actualización del mismo archivo de base de datos al mismo tiempo.

+1

Hago eso en una de mis aplicaciones sin ningún problema ... sqlite bloquea el archivo de la base de datos durante las operaciones de escritura, por lo que en realidad son atómicas (y, por lo tanto, seguras para la ejecución de subprocesos) en un sistema de archivos. –

9

Lo más probable es que el (los) proceso (s) de la base de datos mueran durante una E/S. Por ejemplo, por un asesino de tareas, o si permite que las operaciones de escritura db continúen durante un tiempo en el que la aplicación se apague o duerma ...

Vea si puede reproducir el problema colocando su aplicación en una BD escrita bucle y usando un asesino de tareas en él.

Escenario: se escribieron 32 bytes en la base de datos, la tarea del escritor se destruye después de escribir solo 10, resultado: la base de datos se dejó en estado inconsistente y posiblemente corrupto.

Véase también: Android process killer

EDIT: abrir y cerrar la base de datos para cada lectura/escritura? ¡Para! :)

+0

Gracias, en realidad volví aquí para informar exactamente eso. Puedo volver a crearlo con una aplicación asesina de tareas. Según este artículo, es un error en SQL lite: http://www.pubbs.net/201003/sqlite/60719-sqlite-android-database-corruption.html –

+0

Además, la razón por la que intento abrir y cerrar el DB para cada escritura es para evitar este problema. ¿No resolvería eso el problema? El usuario debería tener mucha suerte y matarlo entre abrir y cerrar. –

+0

Dependiendo de la frecuencia con la que escriba en la base de datos, podría ayudarlo o perjudicarlo. el abrir/cerrar puede agregar suficiente sobrecarga que las escrituras frecuentes más abrir/cerrar deja una ventana más grande para que ocurran los problemas. Por otro lado, si escribe con poca frecuencia, el abrir/cerrar puede vaciar los bytes en "disco" para que no se queden en la memoria y corran el riesgo de perderse. Probablemente agregue un gran mensaje desagradable que se muestre si el usuario daña la base de datos."¡HEY IDIOTO ESTÁS ARRUINANDO TU TELÉFONO AL MATAR TAREAS!" :) –

1

Implemente un proceso de respaldo de db cada día, y si la base de datos se corrompe, simplemente reemplace la base de datos con una copia de seguridad. Puede utilizar métodos simples de copiar y pegar archivos para mantener una copia de seguridad todos los días.

+0

Gracias, pero el DB contiene información de sesión por lo que no es muy factible hacer una copia de seguridad. Los datos cambian minuto a minuto y es crucial para que la aplicación se ejecute. –

+0

Todavía es una forma de respaldo para seguir si no quiere perder todo. Sé que esto es lo último en la tierra que hacer. – Pentium10

1

Como no puedo hacer ningún comentario -pero sí- en la publicación de Brad.

Tengo que aceptar la sobrecarga adicional.

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

teléfonos Android son muy diferentes extremos de la $$$

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

Las personas que ejecutan task killers arruinan sus teléfonos Android.

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

También el new declaración en Android es muy caro.

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

La programación de Android tiene que ver con la reutilización de la memoria preciosa. (HTC Magics/Dreams solo tiene 96 MB disponible para las aplicaciones, y la mayoría 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 NUEVA conexión cada vez que quiera leer o escribir en él.

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.

+0

Todavía está sucediendo aproximadamente 5 veces al día, así que estoy bastante seguro de que no se trata solo de personas que usan asesinos de tareas. Acabo de descubrir que a veces puedo causar la misma excepción usando un asesino de tareas. En cuanto a abrir y cerrar la conexión de base de datos cada vez, solo estaba señalando que estoy dispuesto a agregar la sobrecarga adicional siempre que el DB no se corrompe (aunque no estoy seguro de si la apertura/cierre realmente resolverá el problema, lo estoy intentando todo) –

+0

Podría ser un error SQLite en Android, pero los dispositivos Android normalmente tienen recursos muy limitados. Por lo tanto, crear la menor sobrecarga posible mejorará la velocidad y la estabilidad de cualquier aplicación de Android. Parece que estás creando basura innecesaria por consulta. El lowMemoryKiller del sistema operativo probablemente puede crear los mismos problemas que un asesino de tareas. Como su aplicación no es tan importante como los otros servicios del sistema. – Brian

Cuestiones relacionadas