Android 尝试重新打开已关闭的对象
对于同一数据库中的三个表,我有一个数据库助手类和三个数据源类。 通过异步任务在许多地方访问数据库。我遇到了“尝试重新打开已关闭的对象…”的问题,我四处搜索,发现Android 尝试重新打开已关闭的对象,android,sqlite,Android,Sqlite,对于同一数据库中的三个表,我有一个数据库助手类和三个数据源类。 通过异步任务在许多地方访问数据库。我遇到了“尝试重新打开已关闭的对象…”的问题,我四处搜索,发现dbhelper.getReadableDatabase()为已打开的连接返回相同的对象。我猜问题一定是由于两个线程同时执行操作,其中一个线程完成任务并调用close()连接关闭,运行线程抛出此异常。 因此,为了避免close()我编写了以下两种方法: public static synchronized void newOpenRequ
dbhelper.getReadableDatabase()
为已打开的连接返回相同的对象。我猜问题一定是由于两个线程同时执行操作,其中一个线程完成任务并调用close()
连接关闭,运行线程抛出此异常。
因此,为了避免close()
我编写了以下两种方法:
public static synchronized void newOpenRequest() {
requestsOpen++;
Util.debuglog(TAG, "Open requests: " + requestsOpen);
}
public static synchronized boolean canClose() {
requestsOpen--;
Util.debuglog(TAG, "Open requests: " + requestsOpen);
if(requestsOpen == 0)
return true;
return false;
}
在所有三个数据源类中,当我以以下方式执行此操作时:
private void openRead() {
database = dbhelper.getReadableDatabase();
DBHelper.newOpenRequest();
Log.i(TAG, "Database opened.");
}
private void openWrite() {
database = dbhelper.getWritableDatabase();
DBHelper.newOpenRequest();
Log.i(TAG, "Database opened.");
}
private void close() {
if (DBHelper.canClose()) {
dbhelper.close();
Util.debuglog(TAG, "Database closed.");
}
}
我的LogCat输出如下:
如黑色矩形突出显示的,总的openRequests
为0,所以数据库关闭,正常,但如红色矩形突出显示的,
首先,openRequests
为0,所以只需关闭时间数据库,但是(我猜)发生的是canClose()
在调用dbhelper.close()之前,线程返回true代码>另一个名为open()
的线程(因为openRequests=1在关闭之前就在LogCat上),然后调用第一个线程的close()
,给另一个正在运行的线程带来麻烦
因此,我们正在寻找解决方案来避免这种并发访问问题。
谢谢。我学会了在android中永远不要关闭数据库。所以也许你的解决办法是不关闭数据库。没有任何意义,在应用程序的整个生命周期中保持打开状态。当你的应用程序id被销毁时,Android将释放该资源
您不需要同步数据库调用,因为sqlite可以是线程安全的
DBOpenHelper工作正常:
public class DBOpenHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 31;
private static DBOpenHelper mInstance;
private static final String DATABASE_NAME = "thedb.db";
public static DBOpenHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DBOpenHelper(context.getApplicationContext());
}
return mInstance;
}
private DBOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
使用db助手采样-关闭光标,但不关闭db
SQLiteDatabase db = DBOpenHelper.getInstance(context).getWritableDatabase();
Cursor cursor = null;
try {
cursor = db.query...
}
finally {
cursor.close();
}
requestsOpen
avolatile
字段吗?@PedroOliveira没有,但我想使用同步方法会在这里产生volatile的效果。我不确定。但是,由于您可以同时调用close和open(因为它们相互依赖地同步),因此可以通过不同的任务同时更改该值。为什么不让数据库实例在单例中打开,并从异步任务访问它?@PedroOliveira我必须更改很多现有代码,我也尝试过,在某种程度上,我保持DBHelper单例,将方法从数据源类打开和关闭到它,但在调用DBHelper.close()时,它自己递归调用,导致溢出,花了太多时间检查原因,但无法。所以实现了这个逻辑。@PedroOliveira我想在一个同步函数中结合以上三件事1)newOpenRequest()2)canClose()3)我将在检查'requestsOpen==0后立即关闭同一函数中的db连接。你认为它会有帮助吗?是的,我读到它对于同一个连接池是线程安全的,但是我遇到了问题,因为使用close-only。保持连接畅通真的是个好主意吗?因为我的应用程序还使用该服务处理来自服务器的传入推送消息,服务器再次访问数据库,所以我的连接将永远保持打开状态。我有许多android应用程序正在生产中,我们不会关闭数据库。如果卸载应用程序,操作系统将释放db文件上的锁。打开和关闭是不必要的开销,会导致您所描述的问题。这篇文章:讨论如何在onDestroy生命周期方法中关闭它。我在这里学到的教训是,打开连接不是坏事,它只是文件上的一个锁。让它永远开着。