2011-12-02 56 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

還要檢查內容提供商的多進程標誌清單。每個進程都有一個到數據庫的單獨連接。