Использование шаблона проектирования Singleton для SQLiteDatabase

63

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

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

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

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

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

Теги:
singleton
android-loadermanager

2 ответа

93
Лучший ответ

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


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

Подход №1: имеет `SQLiteOpenHelper` статический член данных

Это не полная реализация, но она должна дать вам представление о том, как правильно спроектировать класс DatabaseHelper. Статический метод factory гарантирует, что в любой момент существует только один экземпляр 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, поэтому, если вы хотите, чтобы Activity или Fragment реализовал LoaderManager.LoaderCallbacks<Cursor> с CursorLoader (который я предлагаю вам воспользоваться, это волшебство!), вам потребуется реализовать ContentProvider для вашего приложения. Кроме того, вам не нужно беспокоиться о создании помощника базы данных Singleton с ContentProviders. Просто вызовите getContentResolver() из Activity, и система позаботится обо всем для вас (другими словами, нет необходимости в создании шаблона Singleton, чтобы предотвратить создание нескольких экземпляров).

Надеюсь, это поможет!

  • 0
    Алекс, я использую твой подход (# 2) и мне нравится его простота. Но недавно я заметил проблему. Интересно, можете ли вы помочь мне с этой проблемой: stackoverflow.com/questions/10972719/… Кстати, только что заметил, что я использую статический mCxt (забыл почему). Интересно, это как-то связано с моей проблемой?
  • 0
    Ссылка выше не работает ... вот обновленная: android-developers.blogspot.com/2009/01/…
Показать ещё 8 комментариев
16

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

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

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

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

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

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

  • 0
    Спасибо Стефан. Вот статьи, которые я использовал в качестве основы: stackoverflow.com/questions/2647542/… stackoverflow.com/questions/4302286/… С уважением, Дэн
  • 0
    Проблема с тем, что вы комментируете, заключается в том, что (AFAIK) использование разных соединений с одной и той же базой данных является причиной отказа. Таким образом, использование синглтона.
Показать ещё 1 комментарий
Сообщество Overcoder
Наверх
Меню