2017-06-15 31 views
0

我一直得到這惱人的運行時錯誤幾個小時,墜毀我的應用程序:什麼時候應該關閉SQLiteDatabase對象?

了java.lang.RuntimeException:執行 doInBackground發生錯誤()。

產生的原因:java.lang.IllegalStateException:嘗試 重新打開已關閉的對象:SQLiteDatabase

一些調試,我發現這是因爲我閉上SQLiteDatabse對象後,在onDestory()方法。當我撥打SQLiteOpenHelper.close()時也會發生這種情況。

@Override 
protected void onDestroy() { 
    super.onDestroy(); 
    _cursor.close(); //is fine 
    _db.close(); //causes error 
    _databaseHelper.close(); //causes error too (probably calls db.close() internally..?) 
    SharedFunctions.d("closed!"); //ignore this ugly thing 
} 

這帶來了兩個問題

  1. 我這樣做對嗎? (可能不是)
  2. 需要關閉SQLiteDatabase對象,如果不是在onDestroy方法?

編輯: 的DB和輔助類是靜態的:

public class MainActivity extends Activity { 

    private Cursor _cursor = null; 
    private MyCursorAdapter _myCursorAdapter = null; 
    private ListView _listView = null; 

    private static SalaryDatabaseHelper _databaseHelper = null; 
    public static SQLiteDatabase db = null; 

    ... 

我初始化_databaseHelper在onCreate()方法:

//get database helper 
     if(_databaseHelper == null) 
      _databaseHelper = SalaryDatabaseHelper.getInstance(this); 

dbAsyncTask.doInBackground()被初始化:

protected Boolean doInBackground(Integer... data) 
{ 
    try { 
     //get writable database 
     if(db == null) 
      db = SalaryDatabaseHelper.getDbInstance(); 

我用單身的輔助類和數據庫類:(都是通過輔助類訪問)

class MyDatabaseHelper extends SQLiteOpenHelper{ 

    private static SalaryDatabaseHelper _instance = null; 
    private static SQLiteDatabase _dbInstance = null; 

    //singletons 
    public static synchronized SalaryDatabaseHelper getInstance(Context context) 
    { 
     // Use the application context, which will ensure that you 
     // don't accidentally leak an Activity's context. 
     if (_instance == null) 
      _instance = new SalaryDatabaseHelper(context.getApplicationContext()); 

     return _instance; 
    } 

    public static synchronized SQLiteDatabase getDbInstance() { 
     if(_dbInstance == null) 
      _dbInstance = _instance.getWritableDatabase(); 

     return _dbInstance; 
    } 

    ... 
+0

什麼是_db?什麼是_databaseHelper?這些常規或靜態字段?這個異常在哪裏被提出? – CommonsWare

+0

我加了一些代碼 – Pilpel

回答

2

SQLiteOpenHelper例如static,因此,在全球範圍。考慮到這一點:

我在做對吧? (可能不是)

我什麼時候需要關閉一個SQLiteDatabase對象,如果不是在的onDestroy方法?

從來沒有。 SQLite是事務性的。沒有關閉數據庫的風險。

是的,這惹惱了我太多,但我已經經歷悲痛這七個階段走了,我就到「接受」

一些簡單場景,那裏是訪問一個單一組分到數據庫時,您可能會在該組件被銷燬時關閉它。在你的情況下,你的整個應用程序,包括後臺線程,都可以訪問數據庫。在這種情況下,你根本就不會關閉它。

+0

那麼它什麼時候關閉?只有當用戶手動終止應用程序?另外,SQLiteDatabase和SQLiteOpenHelper聲明爲靜態是錯誤的嗎? – Pilpel

+0

@Pilpel:「那它什麼時候關閉?」 - 它不會調用'close()'方法。最終,你的過程終止,你的所有對象都消失了,包括你的'SQLiteOpenHelper'和'SQLiteDatabase'。 「將SQLiteDatabase和SQLiteOpenHelper聲明爲靜態是錯誤的嗎?」 - 有一個'static'' SQLiteOpenHelper',或者有一些其他單例持有'SQLiteOpenHelper',這很常見。我不會把'SQLiteDatabase'作爲任何地方的字段;調用幫助器上的'getWritableDatabase()'來獲取它。 – CommonsWare

+0

@Pilpel:另外,對於'static'' SQLiteOpenHelper',你沒有[正確地執行雙重檢查鎖定](https://stackoverflow.com/a/18093774/115145)。如果您將字段設置爲「static volatile」而不是「static」,那麼您應該可以。 – CommonsWare

1

真的,你不必關閉數據庫連接。 您可以將數據庫保存爲Application對象中的字段。

官方文檔沒有提及數據庫關閉的時間。另外this question引用Google工程師 的一箇舊的(現已刪除)帖子,其中說,這種方法是可以的。

而在實際應用中,它多年來運行良好。

相關問題