2009-09-27 69 views
42

我在5月份在[android-developers] Google群组上发布了this。我从来没有听到过,直到上周我的一个学生做了这个问题才得以重现。我想我会把它放在这里,看看它是否为任何人响了。例外:尝试获取关闭SQLiteClosable上的引用

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

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) 

这是没有意义的我。数据库绝对是开放的。该 SQLiteClosableSQLiteQueryDriver创建的SQLiteQuery,我 看到任何证据表明存在一个对象池或东西会在这里 可能解释了为什么一个“新” SQLiteClosable已经关闭。事实上,它是零星的(意味着相同的UI操作有时会触发异常,但并不总是)建议某种游泳池,种族 条件,或其他...但我不知道在哪里。

想法?

谢谢!

UPDATE:有问题的代码来自我的Android Programming Tutorials书中的LunchList教程。它有点分散,不太适合直接在SO中发布。如果你想看看它,你可以从上面的链接下载该书的代码。我不记得该学生当时正在编写的教程的哪个版本,尽管它在Tutorial 12-Tutorial 16范围内。我主要希望碰到一个曾经绊倒过这个问题的人,并且有可能是罪魁祸首。我很确定我的数据库是开放的。再次感谢!

+0

你有没有在这方面取得任何进展? – 2009-10-10 09:34:35

+0

查看我刚添加到原始查询中的更新。这种情况很少发生,我并不担心;我只是希望以前有问题的人会看到这个问题。谢谢! – CommonsWare 2009-10-10 12:00:17

+0

是的,我也很少发生这种情况。尽管如此,我还是希望至少能找到一份关于它的错误报告,但我没有。 – 2009-10-11 06:36:25

回答

50

这一个让我疯狂了最长的时间。我找到的解决方案非常简单:不要保留对SQLiteDatabase对象的引用。相反,请使用SQLiteOpenHelper,每次需要时请致电getWritableDatabase()。从文档:

公共同步SQLiteDatabase getWritableDatabase()

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

答案是一直在那里。

+1

嗯......这很有趣。它也看起来像你可以在SQLiteOpenHelper上调用close()来关闭数据库。我必须对此进行试验。非常感谢! – CommonsWare 2010-03-20 23:16:33

+0

非常欢迎!谢谢你提出这个问题;它帮助我找出解决方案。 – 2010-03-21 02:02:22

+0

无法完全了解它。你能发表更详细的例子吗? – Codevalley 2010-07-26 18:44:24

1

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

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

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

1

我一直在遇到类似的问题,尽管已经跟随Jarett's advice。在我看来,这个问题在定位方面的变化是相当规律的。我发现,由于某种原因,我还没有深入到底,我的代码在方向更改上生成了两个完全相同的AsyncTasks(与活动正常启动时的相反)。这些任务从不同的线程同时执行相同的数据库查询。

这个异常(或偶尔会有其他的SQLiteException)是结果。所以看起来这个消息可能是并发问题的一个症状,即使它不一定是这里发布的原始问题的根源。

+0

当屏幕方向更改时创建一个新的活动。如果您在Activity的onCreate()方法中启动AsyncTasks,则会创建两个。 – 2010-12-01 17:03:26

+0

如果你正确地扩展'SQLiteOpenHelper'并在'onDestroy()'中关闭你的数据库,那么你不应该有任何并发​​调用修改数据库的问题。 – 2011-02-02 02:12:58

8

SQLiteDatabase在某些情况下会自动关闭。光标的

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

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

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

+0

非常感谢这个信息!我不知道数据库可以通过调用getCount()来关闭。 – danh32 2013-05-03 19:26:39

相关问题