我读到SQLiteDatabase
使用引用计数来管理同时查询同一个数据库的两个线程,但它对我不起作用。
SQLiteDatabase
的同一个实例上调用getWriteableDatabase()
来获取SQLiteOpenHelper
个对象。SQLiteDatabase.query()
运行查询。SQLiteOpenHelper.close()
SQLiteDatabase.query()
时抛出此异常:
java.lang.IllegalStateException:尝试重新打开已经关闭的 对象:SQLiteDatabase: /data/user/0/com.comet.android.TypeSmart/databases/en.dic
我也尝试拨打SQLiteDatabase.close()
而不是SQLiteOpenHelper.close()
,但它没有帮助。 :(
引用计数是不是应该阻止这个?
答案 0 :(得分:0)
关于nfrolov说的话:
Android已在内部实现引用计数。基本上,无论何时对SQLiteDatabase执行任何操作,它都会递增计数器,当您完成后,它会递减计数器。 完成所有操作后,数据库只会自行关闭。我完全没有理由再次猜测这个系统。只是不要关闭数据库。你必须关闭游标。
参考:https://nfrolov.wordpress.com/2014/08/16/android-sqlitedatabase-locking-and-multi-threading/
但是不关闭数据库可能会导致:
Leak found
Caused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed
有一个解决方案,你将实现一个AtomicInteger
,你将在其中计算你打开数据库的次数,然后在你即将关闭时递减它,当它达到0时,就是时间你要关闭它。
public class DatabaseManager {
private AtomicInteger mOpenCounter = new AtomicInteger();
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;
public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
}
public static synchronized DatabaseManager getInstance() {
if (instance == null) {
throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
" is not initialized, call initializeInstance(..) method first.");
}
return instance;
}
public synchronized SQLiteDatabase openDatabase() {
if(mOpenCounter.incrementAndGet() == 1) {
// Opening new database
mDatabase = mDatabaseHelper.getWritableDatabase();
}
return mDatabase;
}
public synchronized void closeDatabase() {
if(mOpenCounter.decrementAndGet() == 0) {
// Closing database
mDatabase.close();
}
}
}
据Dmytro Danylyk说:
每次需要数据库时,都应该调用DatabaseManager类的openDatabase()方法。在这个方法中,我们有一个计数器,它指示数据库的打开次数。如果它等于1,则意味着我们需要创建新的数据库。如果没有,则已创建数据库。
在closeDatabase()方法中也是如此。每当我们称这种方法时,计数器就会减少;每当它变为零时,我们正在关闭数据库。
完整示例参考:https://blog.lemberg.co.uk/concurrent-database-access