2017-06-15 114 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工程师 的一个旧的(现已删除)帖子,其中说,这种方法是可以的。

而在实际应用中,它多年来运行良好。

相关问题