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
a
volatile
字段吗?@PedroOliveira没有,但我想使用同步方法会在这里产生volatile的效果。我不确定。但是,由于您可以同时调用close和open(因为它们相互依赖地同步),因此可以通过不同的任务同时更改该值。为什么不让数据库实例在单例中打开,并从异步任务访问它?@PedroOliveira我必须更改很多现有代码,我也尝试过,在某种程度上,我保持DBHelper单例,将方法从数据源类打开和关闭到它,但在调用DBHelper.close()时,它自己递归调用,导致溢出,花了太多时间检查原因,但无法。所以实现了这个逻辑。@PedroOliveira我想在一个同步函数中结合以上三件事1)newOpenRequest()2)canClose()3)我将在检查'requestsOpen==0后立即关闭同一函数中的db连接。你认为它会有帮助吗?是的,我读到它对于同一个连接池是线程安全的,但是我遇到了问题,因为使用close-only。保持连接畅通真的是个好主意吗?因为我的应用程序还使用该服务处理来自服务器的传入推送消息,服务器再次访问数据库,所以我的连接将永远保持打开状态。我有许多android应用程序正在生产中,我们不会关闭数据库。如果卸载应用程序,操作系统将释放db文件上的锁。打开和关闭是不必要的开销,会导致您所描述的问题。这篇文章:讨论如何在onDestroy生命周期方法中关闭它。我在这里学到的教训是,打开连接不是坏事,它只是文件上的一个锁。让它永远开着。