扩展 elhadi 的回答我在跨多个异步任务打开和关闭数据库连接时遇到了类似的问题。根据我当时的调查,很明显没有必要经常打开和关闭数据库连接。我最终采用的方法是对Application 进行子类化,并在onCreate 期间执行单个数据库打开和onTerminate 期间执行单个数据库关闭。然后我设置了一个静态 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;
}
}
回读 JavaDoc 我肯定从某个地方 plagerised 这个但是这个静态的单个 db open/close 解决了你遇到的这个问题。 SO上有另一个答案描述这个解决方案。
更多详情:
针对 Fr4nz 关于下面 NPE 的评论,我提供了我们具体实现的更多细节。
短版
如果没有对广播接收器有很好的了解,很难掌握下面的“全貌”。在您的情况下(并且首先)添加您的数据库创建代码并在创建数据库后初始化并打开数据库。所以写;
try {
database = SQLiteDatabase.openDatabase("/data/data/<yourdbpath>", null, SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException e) {
// Create your database here!
database = SQLiteDatabase.openDatabase("/data/data/<your db path>", null, SQLiteDatabase.OPEN_READWRITE);
}
}
加长版
是的,除了上面的代码之外,还有更多内容。请注意我对第一个实例中的异常捕获的评论(即您的应用程序第一次运行时)。这里是说,“我们的应用程序触发了一个产生数据库创建任务的事件”。在我们的应用程序中实际发生的是注册了一个监听器(Android 的BroadcastReceiver 框架),并且主要应用程序活动所做的第一件事就是检查MainApplication 中的database 静态变量不为空。如果它为空,则生成一个创建数据库的异步任务,当它完成时(即运行onPostExecute() 方法)最终触发我们知道将由我们在try-catch 中注册的侦听器拾取的事件.接收器作为内部类存在于 MainApplication 类下,如下所示;
/**
* 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);
}
}
所以第一次安装的启动过程总结是这样的;
- 类:MainApplication,角色-检查是否有数据库?
- 是吗?数据库变量已初始化
- 没有?接收方已注册 (
OpenDatabaseReceiver)
- 类:MainActivity:应用程序的角色登陆活动,最初检查数据库变量是否为空。
-
database 为空?不添加执行 I/O 的片段,并在对话框中添加“创建应用程序数据库”或类似内容。
-
database 不为空?继续主应用程序执行流程,添加由 db 支持的列表等
- 类:DatabaseCreationDialogFragment:角色 - 生成异步任务以创建数据库。
- 注册新的接收器以监听数据库何时创建。
- 在收集“我已创建数据库”消息时,会触发另一个事件(来自接收方),告诉应用打开数据库。
- 类:MainApplication:角色 2- 侦听“数据库已创建”消息。
- 上述接收器 (
OpenDatabaseReceiver) 打开数据库并广播(通过另一个事件!)数据库已准备好使用。
- 类:MainActivity:角色 2 - 获取“数据库已准备就绪”消息,摆脱“我们正在创建数据库”对话框,继续在应用中显示数据/功能。
和平恢复了。