在elhadi的回答基础上,我遇到了类似的问题,即在多个异步任务中打开和关闭数据库连接。经过我的调查发现,不必要一直打开和关闭数据库连接。我最终采用的方法是对Application
进行子类化,在onCreate
期间执行单个数据库打开操作,onTerminate
期间执行单个数据库关闭操作。然后设置一个静态getter来检索已经打开的SQLiteDatabase
对象。虽然这种方式不太适合DI(依赖注入),但安卓目前还无法完全实现依赖注入。
实现方法如下:
public class MainApplication extends Application {
private static SQLiteDatabase database;
@Override
public void onCreate() {
super.onCreate();
try {
database = SQLiteDatabase.openDatabase("/data/data/<yourdbpath>", null, SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException e) {
}
}
@Override
public void onTerminate() {
super.onTerminate();
if (database != null && database.isOpen()) {
database.close();
}
}
public static SQLiteDatabase getOpenDatabase() {
return database;
}
}
阅读JavaDoc后,我肯定是从某个地方抄袭了这个代码,但是这个静态的单一数据库开/关解决了你遇到的问题。在SO上有另一个答案描述了这种解决方案。
更多细节:
针对Fr4nz以下的NPE评论,我提供了我们特定实现的更多细节。
简短版本:
如果您没有很好地理解BroadcastReceivers,则很难掌握下面的“完整图像”。在您的情况下(首次启动),请在创建数据库之后添加您的DB创建代码并初始化和打开数据库。因此,请编写;
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 类的内部类存在,如下所示:
public class OpenDatabaseReceiver extends BroadcastReceiver {
public static final String BROADCAST_DATABASE_READY = "oceanlife.core.MainApplication$OpenDatabaseReceiver.BROADCAST_DATABASE_READY";
@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);
final Intent databaseReady = new Intent();
databaseReady.setAction(BROADCAST_DATABASE_READY);
context.sendBroadcast(databaseReady);
}
}
因此,首次安装的启动过程概述如下:
- 类:MainApplication,角色-检查是否存在数据库?
- 是?database变量被初始化
- 否?注册接收器(OpenDatabaseReceiver)
- 类:MainActivity,角色-应用程序的着陆活动,并最初检查数据库变量不为空。
- database为null?不添加执行I/O的片段,并添加对话框,显示“正在创建应用程序数据库”或类似消息。
- database不为null?继续主应用程序执行流程,添加由db支持的列表等
- 类:DatabaseCreationDialogFragment,角色-生成异步任务以创建数据库。
- 注册新的接收器,监听何时创建了数据库。
- 在收集到“我已经创建了数据库”消息后,从接收器触发另一个事件,告知应用程序打开数据库。
- 类:MainApplication,角色2-侦听“数据库已创建”消息。
- 上述接收器(OpenDatabaseReceiver)打开数据库并广播(通过另一个事件!),表示该数据库已准备好使用。
- 类:MainActivity,角色2-获取“数据库已准备就绪”消息,去除“我们正在创建数据库”的对话框,并开始显示应用程序中的数据/功能。
和平恢复了。