Расширяя ответ elhadi, я сталкивался с похожими проблемами при открытии и закрытии соединений с базой данных для нескольких асинхронных задач. Из моего расследования в то время стало ясно, что нет необходимости постоянно открывать и закрывать соединения с БД. Подход, который я в конечном итоге принял, заключался в создании подкласса Application
и выполнении одного открытия базы данных во время onCreate
и одного закрытия базы данных onTerminate
. Затем я настроил статический геттер для получения уже открытого объекта 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 назад, я, конечно, где-то воспользовался этим, но это статическое открытие / закрытие одиночной базы данных решило эту проблему, с которой вы столкнулись. На SO есть еще один ответ, описывающий это решение.
Подробнее:
В ответ на комментарий Fr4nz о NPE ниже я предоставил более подробную информацию о нашей конкретной реализации.
Краткая версия
Приведенную ниже «полную картину» трудно понять без хорошего понимания BroadcastReceivers. В вашем случае (и в первую очередь) добавьте код создания БД, инициализируйте и откройте базу данных после того, как вы создали базу данных. Так что пишите;
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
framework) регистрируется, и одна из первых вещей, которую делает основное действие приложения, — это проверка того, что статическая переменная database
в MainApplication
не равна нулю. Если он равен нулю, то создается асинхронная задача, которая создает базу данных, которая по завершении (т. е. запуск метода 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);
}
}
Таким образом, краткое изложение процесса запуска для первой установки выглядит так;
- Class: MainApplication, role- check there is a database?
- Yes? database variable is initialised
- Нет? Получатель зарегистрирован (
OpenDatabaseReceiver
)
- Class: MainActivity: role- landing activity for the application and initially checks that the database variable is not null.
database
is null? Does not add in the fragments that perform I/O and adds in dialog saying "creating the application database" or similar.
database
не является нулевым? Продолжает основной поток выполнения приложения, добавляет в списки, поддерживаемые БД и т. д.
- Class: DatabaseCreationDialogFragment: role- spawns async task to create the database.
- Registers new receiver listening for when the database has been created.
- При сборе сообщения «Я создал базу данных» запускается другое событие (от получателя), сообщающее приложению, что нужно открыть базу данных.
- Class: MainApplication: role 2- listen for the "database created" message.
- Receiver described above (
OpenDatabaseReceiver
) opens the database and broadcast (by another event!) that the database is ready to be used.
- Класс: MainActivity: роль 2. Получает сообщение «база данных готова», избавляется от диалога «мы создаем базу данных» и продолжает отображать данные/функции в приложении.
Мир восстановлен.
person
BrantApps
schedule
29.05.2012