2011-12-02 74 views
5

当我有一个运行在已启动并绑定到活动中一个单独的进程服务活动的应用程序。该服务包含一个处理器,用于发布可延迟运行的runnable。“错误代码5:数据库被锁定”使用的ContentProvider

我想每个组件登录到数据库,所以我实现了与数据库访问涉及内容提供商和我通过扩展的AsyncTask子类调用它从服务或活动。

这一切精美的作品在模拟器上,但是当我在调试我的手机上运行它,我得到我的数据库写零星的数据库锁定错误:

UPDATE

我做了一些改动我的数据库处理和错误稍微改变了。

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) 

我没有把太多的细节之前,因为我认为这是不同的进程或线程的问题,但现在我想这个问题更可能位于代码调用数据库。

问题:

1)为什么我打的锁,当我使用ContentProvider的?
2)为什么不在相应的API 2.3.3仿真器上显示?
3)是否我的代码没有捕获到一个异常,这意味着错误处理得当,我可以忽略它?
4)我在另一个地方看过有人建议调整忙时间。我会怎么做?

,它是这是造成该错误不输于我,我的调试日志记录的讽刺。

如果我解决不了,我的下一个步骤是捆绑日志消息了一个列表,并倾倒出来在一次十批次。

这里是通过代码错误的路径:

活动:

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; 
} 

回答

13

你可能使用多个SQLiteDatabase(或者SQLiteOpenHelper)实例访问数据库?

你只能有一个连接到数据库,否则你会得到您所遇到的错误。

SQLiteDatabase本身是线程安全的,所以你可以同时访问它。

+0

SQLiteDatabase和SQLiteOpenHelper只出现在我的一个类中,这是我的内容提供者中的成员,但我从服务和活动中调用内容提供者。这可以吗? – TomDestry

+0

没关系,只要你只有一个SQLiteOpenHelper,你唯一的SQLiteDatabase实例就是你从SQLiteOpenHelper.getWritableDatabase()(或getReadableDatabase())获得的实例。 – dhaag23

+5

@ dhaag23如果我想要使用多个线程访问数据库,即一个线程用于将数据写入数据库,另一个用于同时从同一数据库读取数据,那么Hw可以使用同一个Helper类的实例吗? – rahul

0

还要检查内容提供商的多进程标志清单。每个进程都有一个到数据库的单独连接。

相关问题