Android

Using Singleton design pattern for SQLiteDatabase

Использование одноэлементного шаблона проектирования для базы данных SQLiteDatabase

Я довольно новичок в Android, и я работаю над простым приложением, чтобы получить некоторый базовый опыт. Мое приложение довольно простое и состоит, среди прочего, из широковещательного приемника и некоторых действий. Оба компонента используют единую базу данных, поэтому теоретически может случиться так, что оба попытаются получить доступ к БД одновременно.

В настоящее время я просто создаю экземпляр объекта db (который является вспомогательным классом SQLite db) каждый раз, когда он мне нужен, и выполняю необходимые операции: запрос, вставка и т.д.

Из того, что я читал здесь и в некоторых других документах, возникает проблема с получением исключения "db locked" в случае одновременного доступа к БД, поэтому лучшим подходом было бы иметь один экземпляр этого объекта БД, чтобы все компоненты всегда использовали одно и то же подключение к БД.

Верны ли приведенные выше рассуждения? Будет ли singleton достаточно хорошим решением для этого? Я знаю, что некоторые пуристы могут возразить против этого, но, пожалуйста, обратите внимание, что это довольно простое приложение, поэтому я могу позволить себе делать то, чего не стал бы делать в других случаях.

В противном случае, какой вариант был бы лучше? Я читал об использовании content provider, но для этого было бы слишком сложно, кроме того, мне не интересно делиться данными с другими действиями. Я действительно прочитал этот пост и нашел его довольно полезным.

Переведено автоматически
Ответ 1

Нажмите здесь, чтобы просмотреть мой пост в блоге на эту тему.


Вот несколько примеров кода, иллюстрирующих три возможных подхода. Они обеспечат доступ к базе данных во всем приложении.

Подход № 1: пусть `SQLiteOpenHelper` будет статическим элементом данных

Это не полная реализация, но она должна дать вам хорошее представление о том, как правильно спроектировать DatabaseHelper класс. Статический заводской метод гарантирует, что в любой момент времени существует только один экземпляр DatabaseHelper.

/**
* create custom DatabaseHelper class that extends SQLiteOpenHelper
*/

public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;

private static final String DATABASE_NAME = "databaseName";
private static final String DATABASE_TABLE = "tableName";
private static final int DATABASE_VERSION = 1;

private Context mCxt;

public static DatabaseHelper getInstance(Context ctx) {
/**
* use the application context as suggested by CommonsWare.
* this will ensure that you dont accidentally leak an Activitys
* context (see this article for more information:
* http://android-developers.blogspot.nl/2009/01/avoiding-memory-leaks.html)
*/

if (mInstance == null) {
mInstance = new DatabaseHelper(ctx.getApplicationContext());
}
return mInstance;
}

/**
* constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/

private DatabaseHelper(Context ctx) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.mCtx = ctx;
}
}

Подход № 2: абстрагируйте базу данных SQLite с помощью `ContentProvider`

Это подход, который я бы предложил. Во-первых, для нового CursorLoader класса требуется ContentProvider s, поэтому, если вы хотите реализовать действие или фрагмент LoaderManager.LoaderCallbacks<Cursor> с помощью CursorLoader (чем я предлагаю вам воспользоваться, это волшебно!), вам нужно реализовать ContentProvider для вашего приложения. Кроме того, вам не нужно беспокоиться о создании помощника по базе данных Singleton с помощью ContentProviders. Просто вызовите getContentResolver() из Activity, и система позаботится обо всем за вас (другими словами, нет необходимости разрабатывать одноэлементный шаблон для предотвращения создания нескольких экземпляров).

Ответ 2

Я никогда не читал об использовании singleton для доступа к базе данных на Android. Не могли бы вы предоставить ссылку на это.

В своих приложениях я использую простые объекты dbhelper, а не одиночные элементы, я думал, что это скорее работа движка sql по обеспечению отсутствия блокировки базы данных, а не работа ваших классов Android, и это довольно хорошо работает для моего самого большого приложения среднего размера.

Обновление # 1: глядя на приведенную вами ссылку, похоже, что проблема вовсе не в использовании разных экземпляров a dbhelper. Даже у одного экземпляра могут возникнуть проблемы с доступом к базам данных: проблема возникает из-за параллельного доступа. Таким образом, единственный способ обеспечить надлежащий доступ к базе данных разными потоками - это использовать простые механизмы синхронизации потоков (synchronized методы или блоки), и это почти не имеет ничего общего с использованием singleton.

Обновление # 2 : вторая предоставленная вами ссылка ясно показывает, что им необходимы одноэлементные объекты dbhelper в случае одновременной записи нескольких потоков в БД. Это может произойти, если вы выполняете sql-операции (вставки / обновления / удаления), например, из AsyncTasks. В этом случае одноэлементный объект dbhelper просто поместил бы все sql-операции в какой-то конвейер и выполнял бы их по порядку.

Это решение может быть проще реализовать, чем использование надлежащей синхронизации потоков с использованием синхронизированных методов в java. На самом деле, я думаю, что где-то в документах Android должно быть больше внимания этой проблеме, и можно было бы поощрять использование помощника singleton db.

Спасибо за этот приятный вопрос и последующие действия.

2023-06-13 23:38 java android sqlite