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

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

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

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

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

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

2 ответа

Решение

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


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

Подход № 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() из Activity, и система позаботится обо всем за вас (другими словами, нет необходимости разрабатывать шаблон Singleton для предотвращения создания нескольких экземпляров).

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

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

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

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

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

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

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

Другие вопросы по тегам