Использование шаблона проектирования Singleton для SQLiteDatabase - PullRequest
70 голосов
/ 02 августа 2011

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

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

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

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

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

Ответы [ 2 ]

96 голосов
/ 15 февраля 2012

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


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

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

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

20 голосов
/ 02 августа 2011

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

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

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

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

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

Спасибо за этот хороший вопрос и продолжение.

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