2011-12-02 11 views
5

Tengo una aplicación que ejecuta una actividad con un servicio en un proceso separado que se inicia y se vincula a la actividad. El servicio contiene un controlador que publica un ejecutable que se ejecutará después de un retraso."código de error 5: la base de datos está bloqueada" cuando se utiliza un ContentProvider

Quiero que cada componente se registre en la base de datos, así que implementé un proveedor de contenido que trata con el acceso a la base de datos y lo llamo desde el servicio o actividad a través de subclases AsyncTask ampliadas.

Todo esto funciona muy bien en el emulador, pero cuando lo ejecuto en depuración en mi teléfono me sale un error de bloqueo de base de datos esporádica en mi forma de escribir la base de datos:

ACTUALIZACIÓN

hice algunos cambios a mi manejo de la base de datos y el error ha cambiado ligeramente.

ERROR/Database(15235): Error inserting MY_MESSAGE 
ERROR/Database(15235): android.database.sqlite.SQLiteException: error code 5: database is locked 
ERROR/Database(15235):  at android.database.sqlite.SQLiteStatement.native_execute(Native Method) 
ERROR/Database(15235):  at android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java:61) 
ERROR/Database(15235):  at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1591) 
ERROR/Database(15235):  at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1435) 
ERROR/Database(15235):  at mypackagename.DatabaseHelper.insertLogging(DatabaseHelper.java:190) 
ERROR/Database(15235):  at mypackagename.ContentProvider.insert(ContentProvider.java:139) 
ERROR/Database(15235):  at android.content.ContentProvider$Transport.insert(ContentProvider.java:198) 
ERROR/Database(15235):  at android.content.ContentResolver.insert(ContentResolver.java:604) 
ERROR/Database(15235):  at mypackagename.Activity$LogToDatabase.doInBackground(Activity.java:642) 
ERROR/Database(15235):  at mypackagename.Activity$LogToDatabase.doInBackground(Activity.java:1) 
ERROR/Database(15235):  at android.os.AsyncTask$2.call(AsyncTask.java:185) 
ERROR/Database(15235):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306) 
ERROR/Database(15235):  at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
ERROR/Database(15235):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088) 
ERROR/Database(15235):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581) 
ERROR/Database(15235):  at java.lang.Thread.run(Thread.java:1019) 

no puse mucho detalle antes de porque pensé que había un problema con los diferentes procesos o hilos, pero ahora estoy pensando que el problema es más probable encuentran en el código llamando a la base de datos.

Preguntas:

1) ¿Por qué estoy golpeando cerraduras cuando estoy usando un ContentProvider?
2) ¿Por qué esto no aparece en un emulador API 2.3.3 equivalente?
3) ¿El hecho de que ninguno de mis códigos capte una excepción significa que el error se manejó correctamente y puedo ignorarlo?
4) Leí en otro lugar a alguien sugiriendo ajustar el tiempo de espera ocupado. ¿Como podría hacerlo?

La ironía de que es mi registro de depuración que está causando el error no se pierde en mí.

Si no puedo resolverlo, mi siguiente paso es agrupar los mensajes de registro en una lista y volcarlos en lotes de diez a la vez.

Aquí es el camino de la a través del código para el error:

Actividad:

private void logDatabaseMessage(String status, String message) 
{ 
    String[] args = {status, message}; 
    LogToDatabase logTask = new LogToDatabase(); 
    logTask.execute(args);  
} 

private class LogToDatabase extends AsyncTask<String, Integer, Void> 
{ 
    @Override 
    protected Void doInBackground(final String... args) 
    { 
     try 
     { 
      SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 
      String dateText = dateFormat.format(new Date()); 

      ContentValues loggingValues = new ContentValues(); 
      loggingValues.put(MyContentProvider.LOGGING_DATETIME, dateText); 
      loggingValues.put(MyContentProvider.LOGGING_STATUS, args[0]); 
      loggingValues.put(MyContentProvider.LOGGING_MESSAGE, args[1]); 
      getContentResolver().insert(MyContentProvider.LOGGING_CONTENT_URI, loggingValues); 
     } 
     catch (Exception ex) 
     { 
      Log.e(TAG, "LogToDatabase.doInBackground threw exception: " + ex.getMessage()); 
      ex.printStackTrace(); 
     }    

     return null; 
    } 
} 

ContentProvider:

@Override 
public Uri insert(Uri uri, ContentValues values) 
{ 
    Uri _uri = null; 
    long rowID = 0; 

    try 
    { 
     switch (uriMatcher.match(uri)) 
     { 
      case LOGGING: 
       rowID = dbHelper.insertLogging(values); 
       if (rowID == 0) 
        throw new SQLException("Failed to insert row into " + uri); 

       _uri = ContentUris.withAppendedId(LOGGING_CONTENT_URI, rowID); 
       break; 

      default: throw new SQLException("Failed to insert row into " + uri); 
     } 

     if (rowID != 0) 
      getContext().getContentResolver().notifyChange(_uri, null);  
    } 
    catch (Exception ex) 
    { 
     Log.e(TAG, LogPrefix + "insert threw exception: " + ex.getMessage()); 
     ex.printStackTrace(); 
    } 

    return _uri;  
} 

DatabaseHelper:

public long insertLogging(ContentValues values) 
{ 
    long rowID = 0; 

    try 
    { 
     rowID = db.insert(LOGGING_TABLE, null, values); 
    } 
    catch (Exception ex) 
    { 
     Log.e(TAG, LogPrefix + "ERROR: Failed to insert into logging table: " + ex.getMessage()); 
     ex.printStackTrace(); 
    } 

    return rowID; 
} 

Respuesta

13

¿Estás posiblemente acceder a la base de datos usando múltiples instancias de SQLiteDatabase (o quizás SQLiteOpenHelper)?

Solo puede tener una conexión a la base de datos, de lo contrario, obtendrá los errores que ha experimentado.

SQLiteDatabase es seguro para subprocesos, por lo que puede acceder a él al mismo tiempo.

+0

SQLiteDatabase y SQLiteOpenHelper aparecen solo en una de mis clases, que es miembro de mi proveedor de contenido, pero llamo al proveedor de contenido tanto del servicio como de la actividad. ¿Eso esta bien? – TomDestry

+0

Eso está bien siempre y cuando solo tenga un SQLiteOpenHelper y su única instancia de SQLiteDatabase sea la que obtenga de SQLiteOpenHelper.getWritableDatabase() (o getReadableDatabase()). – dhaag23

+5

@ dhaag23 Si quiero acceder al DB utilizando varios hilos, es decir, un hilo para escribir datos en el DB y otro para leer desde el mismo DB al mismo tiempo, ¿puedo usar la misma instancia de la clase Helper? – rahul

0

También verifique el indicador de multiproceso del proveedor de contenido en el manifiesto. Cada proceso tendría una conexión separada a la base de datos.

Cuestiones relacionadas