Android sqlite с многопоточностью

Я пишу приложение для Android, используя sqlite. Есть много мероприятий и одна услуга. Я использую БД из более чем одного потока. Он отлично работает в Android 2.X, но как только я запускаю его в Android 3.X, он всегда выдает эту ошибку и Force Close:

05-04 22:17:04.815: I/SqliteDatabaseCpp(8774): sqlite returned: error code = 5, msg = database is locked, db=/data/data/xxx/databases/im
05-04 22:17:04.815: E/SqliteDatabaseCpp(8774): sqlite3_open_v2("/data/data/xxx/databases/im", &handle, 6, NULL) failed
05-04 22:17:04.835: E/SQLiteDatabase(8774): Failed to open the database. closing it.
05-04 22:17:04.835: E/SQLiteDatabase(8774): android.database.sqlite.SQLiteDatabaseLockedException: database is locked
05-04 22:17:04.835: E/SQLiteDatabase(8774):     at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
05-04 22:17:04.835: E/SQLiteDatabase(8774):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:983)
05-04 22:17:04.835: E/SQLiteDatabase(8774):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:956)
05-04 22:17:04.835: E/SQLiteDatabase(8774):     at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1021)
05-04 22:17:04.835: E/SQLiteDatabase(8774):     at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:790)
05-04 22:17:04.835: E/SQLiteDatabase(8774):     at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221)
05-04 22:17:04.835: E/SQLiteDatabase(8774):     at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:149)

Кто-нибудь знает, почему это происходит и как это решить?

Я исследовал в Интернете, и большинство людей советуют:

  1. Используйте одно соединение с БД только для приложения. Как это обеспечить? Я хочу поделиться подключением к БД как для службы, так и для действий. Должен ли я сделать это, создав общедоступную статическую переменную БД?
  2. ContentProvider - я использую сложный оператор SQL в коде (например, объединение нескольких таблиц, временную таблицу). Можно ли запустить эти сложные операторы SQL в ContentProvider?


    Спасибо всем. Наконец, (1) отлично работает для меня. Но мне все равно интересно, почему в Android 2.X нет этой проблемы.

person mobile app Beginner    schedule 04.05.2012    source источник
comment
1) работает, только если весь доступ происходит в рамках одного и того же процесса, 2) работает до тех пор, пока все, что вам нужно, это вставка/запрос/обновление/удаление, но сложные запросы выглядят уродливо, поскольку вы ограничены developer.android.com/reference/android/content/ интерфейс   -  person zapl    schedule 04.05.2012
comment
Спасибо zapl, БД не используется совместно с другими приложениями. Я думаю, что (1) хорошо для меня. У вас есть идеи, почему в Android 2.X нет этой проблемы?   -  person mobile app Beginner    schedule 04.05.2012
comment
вам следует перейти по этой ссылке stackoverflow.com/questions/7930139/android-databse-locked   -  person Anand Tiwari    schedule 04.05.2012
comment
@mobileappBeginner Нет :(   -  person zapl    schedule 04.05.2012
comment
Спасибо, Ананд, я закрыл базу данных и курсор после его использования. Но все равно получаю ошибку   -  person mobile app Beginner    schedule 04.05.2012
comment
Вот оболочка, которую я написал/использую, которая немного упрощает использование SQLite, особенно с потоками, в контексте Android - SqlDb для Android   -  person keios    schedule 31.12.2013


Ответы (2)


Номер 1 - это ответ. У меня есть несколько ответов на стек и сообщений в блогах о том, как именно это сделать:

Каковы лучшие практики для SQLite на Android?

http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection

Номер 2 — это много дополнительной работы и ненужной. ContentProvider существует для того, чтобы вы могли обмениваться данными с другими приложениями. Он используется для управления подключениями к базе данных, потому что люди не понимают, как Sqlite и Android работают вместе.

person Kevin Galligan    schedule 04.05.2012
comment
Спасибо, Кевин Галлиган, я прочитал ваши посты. Я многому научился на - stackoverflow.com/questions/2493331/. Я пробую решение (1). Я изучу ormlite, если решение (1) не сработает. Спасибо! - person mobile app Beginner; 04.05.2012
comment
ORMLite хорош, но совершенно не нужен для доступа к базе данных из нескольких потоков. Просто создайте статический экземпляр SQLiteOpenHelper или сохраните один экземпляр в экземпляре приложения. У вас никогда не будет заблокированных проблем с базой данных, если у вас есть только один экземпляр. - person Kevin Galligan; 04.05.2012
comment
Спасибо, Кевин, ORMLite в любом случае великолепен - person mobile app Beginner; 05.05.2012

Я предлагаю вам использовать ContentProvider с LoaderManager всякий раз, когда вы можете. Он способен автоматически выполнять запросы в фоновом режиме.

person Adrian Monk    schedule 04.05.2012
comment
Спасибо за совет, но он требует много дополнительной работы, и база данных не будет использоваться совместно с другими приложениями. Я думаю, что решение (1) лучше для меня. Я подумаю о предложенном вами решении, если (1) сработает. Спасибо - person mobile app Beginner; 04.05.2012
comment
Я знаю много людей, которые предпочитают ContentProvider, но это совершенно не обязательно для многопоточного доступа к БД. Если вы используете его только для этого, он не нужен. Однако, если вам нравится ContentProvider, используйте его. Хотя мне это кажется дополнительной работой. - person Kevin Galligan; 04.05.2012