代码之家  ›  专栏  ›  技术社区  ›  CommonsWare

异常:尝试在关闭的sqliteClosable上获取引用

  •  43
  • CommonsWare  · 技术社区  · 15 年前

    我张贴 this 回到5月份的[Android开发者]谷歌集团。我从来没有回音,直到上周我的一个学生回答了这个问题,我才得以重现。我想我会把它贴在这里,看看它是否能为任何人敲响警钟。

    在我的一个代码示例中,我有以下方法:

    static Cursor getAll(SQLiteDatabase db, String orderBy) {
            return(db.rawQuery("SELECT * FROM restaurants "+orderBy, null));
    
    }
    

    当我偶尔运行它时,我会得到:

    05-01 14:45:05.849: ERROR/AndroidRuntime(1145):
    java.lang.IllegalStateException: attempt to acquire a reference on a
    close SQLiteClosable
    05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
    android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:31)
    05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
    android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:56)
    05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
    android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:49)
    05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
    android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:49)
    05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
    android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1118)
    05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
    android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1092)
    05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
    apt.tutorial.Restaurant.getAll(Restaurant.java:14)
    

    这对我来说毫无意义。数据库绝对是开放的。这个 SQLiteClosable SQLiteQuery 创建的 SQLiteQueryDriver 和我 看不到任何证据表明这里有一个对象池或发生了什么事情。 这也许可以解释“新的” 可出租的 已关闭。这个 事实上它是零星的(有时意味着相同的UI操作 引发异常,但并非总是如此)表明某种游泳池、比赛 条件,或者什么……但我不知道在哪里。

    思想?

    谢谢!

    更新 :问题代码来自我的午餐清单教程 Android Programming Tutorials 书。它有点散开,不太适合直接在网上发帖。如果你想看一看,可以从上面的链接下载这本书的代码。我不清楚学生当时正在学习哪个版本的教程,尽管它在教程12教程16的范围内。我主要是希望遇到一个曾经因为这个问题绊倒过的人,他很可能是罪魁祸首。我很确定我的数据库是开放的。再次感谢!

    4 回复  |  直到 12 年前
        1
  •  53
  •   Lucifer phtrivier    12 年前

    这一次让我疯狂了很长时间。我找到的解决方案相当简单:不要引用 SQLiteDatabase 物体。相反,使用 SQLiteOpenHelper 并打电话 getWritableDatabase() 每次你需要的时候。来自文档:

    公共同步的sqlitedatabase getwritabledatabase()。

    创建和/或打开将用于读写的数据库。 一旦成功打开,数据库就会被缓存,因此每次需要写入数据库时都可以调用此方法。

    答案一直都在那里。

        2
  •  9
  •   darutk    14 年前

    在某些情况下,sqliteDatabase会自动关闭。

    http://darutk-oboegaki.blogspot.com/2011/03/sqlitedatabase-is-closed-automatically.html

    cursor的getcount()和onmove()方法使用sqliteQuery触发实际查询。在获得所有必需的数据后,sqliteQuery会减少sqliteDatabase实例的引用计数。当引用计数达到0时,数据库将关闭。

    注意,查询可以异步执行,在这种情况下,如果在sqliteQuery完成数据准备之前调用了getcount(),则getcount()可能返回-1。

        3
  •  1
  •   cikabole    15 年前

    几天来我也遇到了同样的问题,我的解决方案是将open()方法放在查询之前,将close()方法放在数据库操作之后。看起来像这样。

    open();
    Cursor cur=db.query(DATABASE_TABLE_CON, null, null, null, null, null, " name ASC");
    close();
    return cur;
    

    它工作得很好,但我担心资源成本。我不确定在采取任何行动之前,我是否会花费更多的资源来打开和关闭数据库。

        4
  •  1
  •   Community CDub    7 年前

    我也遇到过类似的问题,尽管我已经跟踪了 Jarett's advice . 在我的例子中,这个问题经常发生在方向改变上。我发现,出于某种原因,我还没有深入了解,我的代码在方向更改时生成两个相同的、几乎同时进行的异步任务(而不是活动正常启动时只生成一个)。这些任务同时从不同的线程执行相同的数据库查询。

    结果就是这个异常(或者偶尔是其他的sqliteException)。因此,看起来这个消息可能是并发性问题的症状,即使它不一定是这里发布的原始问题的根源。