Android-db中对SQLite数据库的并发访问已关闭
我读了很多关于这个主题的文章,但是没有人能回答我的问题 我从并发线程访问数据库,我的SQLiteOpenHelper实现了singleton的设计模式,所以我的应用程序只有一个实例 我使用如下代码访问我的数据库:Android-db中对SQLite数据库的并发访问已关闭,android,sqlite,sqliteopenhelper,getwritabledatabase,Android,Sqlite,Sqliteopenhelper,Getwritabledatabase,我读了很多关于这个主题的文章,但是没有人能回答我的问题 我从并发线程访问数据库,我的SQLiteOpenHelper实现了singleton的设计模式,所以我的应用程序只有一个实例 我使用如下代码访问我的数据库: SQLiteDatabase db = DatabaseHelper.getInstance().getWritableDatabase(); ... Do some update in the DB ... db.close(); 我不明白为什么我仍然得到“db read
SQLiteDatabase db = DatabaseHelper.getInstance().getWritableDatabase();
...
Do some update in the DB
...
db.close();
我不明白为什么我仍然得到“db ready closed”错误,getWritableDatabase()方法不应该在调用close()之前锁定数据库吗?来自其他线程的其他getWritableDatabase()调用应该等待数据库关闭吗?是这样还是我错过了什么?如果你打电话
DatabaseHelper.getInstance().getWritableDatabase()
在您的线程中,我建议您在启动线程之前管理它。在主程序中打开数据库,调用线程。线程终止后,您将关闭主程序中的数据库。扩展elhadi的回答,在跨多个异步任务打开和关闭数据库连接时,我遇到了类似的问题。从我当时的调查来看,很明显没有必要经常打开和关闭db连接。我最终采用的方法是对
应用程序进行子分类,并在onCreate
期间执行单个db open,在terminate
期间执行单个db close。然后,我设置了一个静态getter来检索已经打开的SQLiteDatabase
对象。不是DI(依赖注入)友好的,但Android还不能真正做到这一点
像这样的东西
public class MainApplication extends Application {
private static SQLiteDatabase database;
/**
* Called when the application is starting, before any other
* application objects have been created. Implementations
* should be as quick as possible...
*/
@Override
public void onCreate() {
super.onCreate();
try {
database = SQLiteDatabase.openDatabase("/data/data/<yourdbpath>", null, SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException e) {
// Our app fires an event spawning the db creation task...
}
}
/**
* Called when the application is stopping. There are no more
* application objects running and the process will exit.
* <p>
* Note: never depend on this method being called; in many
* cases an unneeded application process will simply be killed
* by the kernel without executing any application code...
* <p>
*/
@Override
public void onTerminate() {
super.onTerminate();
if (database != null && database.isOpen()) {
database.close();
}
}
/**
* @return an open database.
*/
public static SQLiteDatabase getOpenDatabase() {
return database;
}
}
/**
* Listener waiting for the application to finish
* creating the database.
* <p>
* Once this has been completed the database is ready for I/O.
* </p>
*
* @author David C Branton
*/
public class OpenDatabaseReceiver extends BroadcastReceiver {
public static final String BROADCAST_DATABASE_READY = "oceanlife.core.MainApplication$OpenDatabaseReceiver.BROADCAST_DATABASE_READY";
/**
* @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
*/
@Override
public void onReceive(final Context context, final Intent intent) {
Log.i(CreatedDatabaseReceiver.class.getSimpleName(), String.format("Received filter event, '%s'", intent.getAction()));
database = SQLiteDatabase.openDatabase("/data/data/<your db path>", null, SQLiteDatabase.OPEN_READWRITE);
unregisterReceiver(openDatabaseReceiver);
// Broadcast event indicating that the creation process has completed.
final Intent databaseReady = new Intent();
databaseReady.setAction(BROADCAST_DATABASE_READY);
context.sendBroadcast(databaseReady);
}
}
因此,第一次安装的启动过程总结如下:
- 是吗?数据库变量已初始化
- 没有?已注册接收器(OpenDatabaseReceiver)
是否为空?不添加执行I/O的片段,并在对话框中添加“创建应用程序数据库”或类似内容数据库
不为空?执行主应用程序执行流,添加db支持的列表等数据库
- 在创建数据库时注册新的侦听接收器
- 在收集“我已经创建了数据库”消息时,会触发另一个事件(来自接收者),通知应用程序打开数据库
- 上面描述的接收器(
)打开数据库并广播(通过另一个事件!)数据库已准备好使用OpenDatabaseReceiver
和平已恢复。是,我在每个线程中调用DatabaseHelper.getInstance().getWritableDatabase()。谢谢你的回答,我要试试这个。但是我的反射理论上正确吗?在您的解决方案中,我应该在启动线程之前调用getWritableDatabase()来启动数据库吗?我真的不知道它应该有什么帮助,因为我仍然需要在我的线程中调用getWritableDatabase(),对吗?如果您尝试这样做,请不要忘记使用新应用程序“name”的路径更新您的
Manifest.xml
。您好,我现在在数据库路径方面遇到一些问题。显然,它找不到DB,getOpenDatabase抛出NullPointerException。我是否可以使用DatabaseHelper.getInstance().getWritableDatabase()等替代openDatabase()(仅一次)?(重要的是)添加了Fr4nz的更多详细信息。读一读,画出一些东西。如果你想知道“长版本”的原因,我们最好在“聊天”中了解。这一切都是关于碎片的角色和责任,并告知用户发生了什么。感谢您的详细回答,我将尝试这个好的总结!(即使概述了一个有点愚蠢的设计——对话框也没有产生线程和接收者的业务)
/**
* Listener waiting for the application to finish
* creating the database.
* <p>
* Once this has been completed the database is ready for I/O.
* </p>
*
* @author David C Branton
*/
public class OpenDatabaseReceiver extends BroadcastReceiver {
public static final String BROADCAST_DATABASE_READY = "oceanlife.core.MainApplication$OpenDatabaseReceiver.BROADCAST_DATABASE_READY";
/**
* @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
*/
@Override
public void onReceive(final Context context, final Intent intent) {
Log.i(CreatedDatabaseReceiver.class.getSimpleName(), String.format("Received filter event, '%s'", intent.getAction()));
database = SQLiteDatabase.openDatabase("/data/data/<your db path>", null, SQLiteDatabase.OPEN_READWRITE);
unregisterReceiver(openDatabaseReceiver);
// Broadcast event indicating that the creation process has completed.
final Intent databaseReady = new Intent();
databaseReady.setAction(BROADCAST_DATABASE_READY);
context.sendBroadcast(databaseReady);
}
}