2014-10-30 44 views
-1

所以我試着使用單獨的線程來保存數據到數據庫,但它會導致異常:安卓:保存在單獨的線程中的數據庫將導致數據庫異常關閉

java.lang.IllegalStateException:數據庫無法打開

我想這是不是一個Loader,因爲我不需要任何導致光標,它只是爲了節省我的數據的任務。保存到db代碼看起來如下:

Thread thread = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     dbHelper.saveMessages(messages); 
    } 
}); 
thread.setPriority(Thread.MIN_PRIORITY); 
thread.start(); 

如果我從一個線程刪除這個數據庫操作一切都很好,但它會導致UI滯後。如果我試圖從單獨的線程讀取數據庫,會發生同樣的情況。
這是一個DB編寫代碼的一部分:

SQLiteDatabase db = dbAdapter.getWritableDatabase()); 
    try { 
     if (existingMessage != null) 
      insertId = db.update(Tables.Messages.TABLE_NAME, values, Tables.Messages.SERVER_ID + "=?", new String[]{String.valueOf(message.serverId)}); 
     else 
      insertId = db.insertOrThrow(Tables.Messages.TABLE_NAME, null, values); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

其實例外發生在db.update(),或在db.insertOrThrow()線。它不保證拋出異常,但它不時。它可以寫入例如5個對象,然後在6日失敗。
我在做什麼錯誤或最新SQLiteOpenHelper錯誤? 完整的異常日誌:

10-30 22:34:52.746 10431-10536/com.myapp W/System.err﹕ java.lang.IllegalStateException: database not open 
10-30 22:34:52.746 10431-10536/com.myapp W/System.err﹕ at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1224) 
10-30 22:34:52.746 10431-10536/com.myapp W/System.err﹕ at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1184) 
10-30 22:34:52.746 10431-10536/com.myapp W/System.err﹕ at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1264) 
10-30 22:34:52.746 10431-10536/com.myapp W/System.err﹕ at com.myapp.db.DatabaseHelper.saveMessages(DatabaseHelper.java:478) 
10-30 22:34:52.746 10431-10536/com.myapp W/System.err﹕ at com.myapp.db.DatabaseHelper.requestMessages(DatabaseHelper.java:1245) 
10-30 22:34:52.746 10431-10536/com.myapp W/System.err﹕ at com.myapp.activity.LoginActivity$9.run(LoginActivity.java:425) 
10-30 22:34:52.746 10431-10536/com.myapp W/System.err﹕ at java.lang.Thread.run(Thread.java:1096) 

UPDATE:
我會發現,它的所有關於從數據庫中實際讀取。在我的代碼中,我首先從db中讀取以確保沒有這樣的記錄。之後,我決定要做什麼 - 插入或更新。這個問題發生在可讀數據庫中。在打開db進行讀取之後,下一行應該從db中讀取,它顯示爲「未打開」。沒有線程可供閱讀,一切都發生在一個線程中:第一次讀取然後寫入。然而閱讀隨機失敗。所以它不像我之前提到的那樣寫。

+0

是什麼在你的代碼它發生的確切堆棧跟蹤和在哪裏呢?發佈'saveMessages()'代碼。 – laalto 2014-10-30 20:04:06

+0

你可能不是非常小心的多線程。看看[這個問題](http://stackoverflow.com/questions/2493331/what-are-the-best-practices-for-sqlite-on-android/3689883)。它的一些答案可能會有所幫助。 – Jakar 2014-10-30 20:32:46

+0

其實我不知道你爲什麼不使用AtomicInteger而不是鎖定一個虛假的對象只是爲了counter ++或 - 。無論如何,我正在使用Dmytro Danylyk的解決方案。然而,我的問題不是關於多線程,因爲沒有其他線程使用db來同時讀取或寫入。 – Stan 2014-10-30 20:50:18

回答

0

我看到您的實現多個問題。第一個dbHelper可以被另一個線程使用,並可能造成死鎖,所以你應該用鎖來保護它。 proceedToNextActivity()看起來確實對UI的一些工作,做從後臺線程什麼是完全錯誤的,並會導致崩潰。

如果dbHelper不需要任何UI元素只是通過郵件的副本此主題,打造dbHelper - >做了一些工作 - >關閉幫手 - >端螺紋。希望這會解決你的問題。

+0

'proceedToNextActivity()'對UI不做任何事情,反正這不是問題的一部分。至於'dbHelper',理論上可以由其他線程使用,但它並不真的 – Stan 2014-10-30 20:25:23

0

做一個插入或更新的方法。如果插入由於重複鍵而失敗,則更新。

+0

-1,這個答案不回答這個問題,並沒有解決拋出的'IllegalStateException'。如果有的話,這應該留作評論。 – Jakar 2014-10-30 23:49:30

+0

我無法想象沒有insert_or_update方法的數據庫。你說過這種更新很可能沒有處理重複密鑰。更新失敗,然後做一個插入。 – danny117 2014-10-31 16:21:59