Answers:
我会一直保持打开状态,并以某种生命周期方法(例如onStop
或)关闭它onDestroy
。这样,您可以在每次使用数据库之前通过调用isDbLockedByCurrentThread
或isDbLockedByOtherThreads
对单个SQLiteDatabase
对象轻松地检查数据库是否已在使用中。这样可以防止对数据库进行多次操作,并避免应用程序崩溃
因此,在您的单例中,您可能有一个像这样的方法来获取单个SQLiteOpenHelper
对象:
private SQLiteDatabase db;
private MyDBOpenHelper mySingletonHelperField;
public MyDBOpenHelper getDbHelper() {
db = mySingletonHelperField.getDatabase();//returns the already created database object in my MyDBOpenHelper class(which extends `SQLiteOpenHelper`)
while(db.isDbLockedByCurrentThread() || db.isDbLockedByOtherThreads()) {
//db is locked, keep looping
}
return mySingletonHelperField;
}
因此,每当您要使用打开的辅助对象时,请调用此getter方法(确保已线程化)
单例中的另一个方法可能是(在尝试调用上述getter之前称为EVERY TIME):
public void setDbHelper(MyDBOpenHelper mySingletonHelperField) {
if(null == this.mySingletonHelperField) {
this.mySingletonHelperField = mySingletonHelperField;
this.mySingletonHelperField.setDb(this.mySingletonHelperField.getWritableDatabase());//creates and sets the database object in the MyDBOpenHelper class
}
}
您可能还希望以单例方式关闭数据库:
public void finalize() throws Throwable {
if(null != mySingletonHelperField)
mySingletonHelperField.close();
if(null != db)
db.close();
super.finalize();
}
如果您的应用程序用户能够非常快速地创建许多数据库交互,则应该使用上面我已经演示过的方法。但是,如果数据库交互最少,我将不必担心,只需每次创建和关闭数据库即可。
到目前为止,无需检查数据库是否已被另一个线程锁定。在每个线程中使用单例SQLiteOpenHelper时,您很安全。从isDbLockedByCurrentThread
文档:
该方法的名称来自与数据库建立活动连接时的时间,这意味着该线程正在对数据库持有实际的锁。如今,不再存在真正的“数据库锁”,尽管如果线程无法获取数据库连接以执行特定操作,它们可能会阻塞。
isDbLockedByOtherThreads
自API级别16开始不推荐使用。
关于这些问题:
我的数据库管理器是一个单例,现在在初始化时打开与数据库的连接。
我们应该划分“打开数据库”,“打开连接”。SQLiteOpenHelper.getWritableDatabase()给出一个打开的数据库。但是我们不必像内部那样控制连接。
确保数据库始终处于打开状态是安全的,这样当有人调用我的班级来使用数据库时,该数据库已经打开了吗?
是的。如果正确关闭事务,连接不会挂起。请注意,如果GC完成,则数据库也会自动关闭。
还是应该在每次访问之前和之后打开和关闭数据库。
关闭SQLiteDatabase实例除了关闭连接没有任何其他好处,但是如果此时有一些连接,这对开发人员来说是不好的。同样,在SQLiteDatabase.close()之后,SQLiteOpenHelper.getWritableDatabase()将返回一个新实例。
始终保持打开状态是否有害?
不,没有。还要注意,在不相关的时刻和线程(例如在Activity.onStop()中)关闭数据库可能会关闭活动连接并使数据保持不一致状态。
Android 8.1具有以下SQLiteOpenHelper.setIdleConnectionTimeout(long)
方法:
设置在关闭SQLite连接并将其从池中删除之前允许SQLite连接空闲的最大毫秒数。
从性能角度来看,最佳方法是在应用程序级别上保留单个SQLiteOpenHelper实例。打开数据库可能会很昂贵并且是一项阻塞操作,因此不应在主线程上和/或在活动生命周期方法中进行打开。
当不使用数据库时,可以使用setIdleConnectionTimeout()方法(在Android 8.1中引入)释放RAM。如果设置了空闲超时,则一段时间不活动之后(即,当未访问数据库时),数据库连接将关闭。当执行新查询时,连接将透明地重新打开到应用程序。
除此之外,应用程序可以在进入后台或检测到内存压力时调用releaseMemory(),例如在onTrimMemory()中
您也可以使用ContentProvider。它将为您完成这些工作。
创建您自己的应用程序上下文,然后从那里打开和关闭数据库。该对象还有一个OnTerminate()方法,您可以用来关闭连接。我还没有尝试过,但这似乎是一个更好的方法。
@binnyb:我不喜欢使用finalize()关闭连接。可能可行,但是据我了解,使用Java finalize()方法编写代码是一个坏主意。
onTerminate
不会被调用在生产环境- developer.android.com/reference/android/app/...