Korzystanie z Singleton design pattern dla SQLiteDatabase

Jestem raczej nowicjuszem na Androidzie i pracuję nad prostą aplikacją, aby uzyskać podstawowe doświadczenie. Moja aplikacja jest dość prosta i składa się między innymi z odbiornika transmisji i niektórych działań. Oba komponenty korzystają z jednej bazy danych, więc teoretycznie może się zdarzyć, że oba będą próbowały uzyskać dostęp do bazy danych jednocześnie.

Obecnie po prostu inicjuję obiekt db (który jest-klasą pomocniczą SQLite db) za każdym razem, gdy go potrzebuję, i wykonuję potrzebne operacje: zapytanie, Wstaw, itp.

Z tego, co czytałem tutaj i w niektórych innych dokumentach, ma to problem z uzyskaniem wyjątku "db locked" w przypadku, gdy db jest dostępny jednocześnie, więc lepszym rozwiązaniem byłoby posiadanie pojedynczej instancji tego obiektu db, więc wszystkie komponenty używają tego samego połączenia db przez cały czas.

Czy powyższe rozumowanie jest poprawne? Czy singleton byłby dobrym rozwiązaniem? Wiem, że niektórzy puryści mogą się temu sprzeciwiać, ale proszę zauważyć, że jest to dość prosta aplikacja, więc mogę sobie pozwolić na robienie rzeczy, których nie robiłbym w innych przypadkach.

W Przeciwnym Razie, co byłoby lepszym rozwiązaniem? Czytałem o korzystaniu z dostawcy treści, ale byłoby to zbyt wiele, poza tym nie jestem zainteresowany dzieleniem się danymi z innymi działaniami. Rzeczywiście przeczytałem to post i okazało się, że to bardzo pomocne.

Author: Suragch, 2011-08-01

2 answers

Kliknij tutaj, aby zobaczyć mój wpis na blogu na ten temat.


Oto przykładowy kod, który ilustruje trzy możliwe podejścia. Umożliwi to dostęp do bazy danych w całej aplikacji.

Podejście # 1: niech` SQLiteOpenHelper ' będzie statycznym członkiem danych

To nie jest pełna implementacja, ale powinna dać ci dobry pomysł, jak poprawnie zaprojektować DatabaseHelper klasę. Statyczna metoda fabryczna zapewnia, że istnieje tylko jedna instancja bazy danych w dowolnym momencie.

/**
 * 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;
    }
}
[[15]} podejście # 2: streszczenie bazy danych SQLite z 'ContentProvider'

Takie podejście bym proponował. Po pierwsze, nowa klasa CursorLoader wymaga ContentProvider s, Więc jeśli chcesz, aby aktywność lub Fragment zaimplementował {[4] } z CursorLoader (co proponuję wykorzystać, to jest magiczne!), musisz zaimplementować ContentProvider dla swojej aplikacji. Co więcej, nie musisz się martwić o tworzenie Singleton database helper z ContentProviders. Po prostu wywołaj getContentResolver() z aktywności, a system zajmie się wszystkim za Ciebie(innymi słowy, nie ma potrzeby projektowania wzorca Singletona, aby zapobiec tworzeniu wielu instancji).

Mam nadzieję, że to pomoże!

 101
Author: Alex Lockwood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-15 19:24:01

Nigdy nie czytałem o używaniu Singletona, aby uzyskać dostęp do db na Androidzie. Czy mógłbyś podać link na ten temat?

W moich aplikacjach, używam prostych obiektów dbhelper, a nie singletons, myślałem, że jest to bardziej zadanie silnika sql, aby upewnić się, że db nie jest zablokowany, a nie zadanie klas Androida, i działa całkiem dobrze dla mojej największej aplikacji, która jest średniej wielkości.

Update # 1: patrząc na referencję, którą podałeś, wygląda na to, że problem nie polega wcale na używaniu różnych instancje dbhelper. Nawet pojedyncza instancja może napotkać problemy z dostępem do baz danych : problem wynika z równoczesnego dostępu. Tak więc jedynym sposobem zapewnienia prawidłowego dostępu do bazy danych przez różne wątki jest użycie prostych mechanizmów synchronizacji wątków (metody lub blokisynchronized), A to prawie nie ma nic wspólnego z użyciem Singletona.

Update # 2: drugi link podasz wyraźnie pokazuje, że ich jest potrzeba dla singleton dbhelper obiektów w przypadku wielu wątki piszące jednocześnie w db. Może się to zdarzyć, jeśli wykonujesz operacje sql (wstawia/aktualizuje/usuwa) z asynchronicznych zadań na przykład. W takim przypadku singleton obiekt dbhelper po prostu umieścić wszystkie operacje sql w jakimś potoku i wykonać je w kolejności.

To rozwiązanie może być łatwiejsze do zaimplementowania niż użycie odpowiedniej synchronizacji wątków przy użyciu zsynchronizowanych metod w Javie. Właściwie myślę, że gdzieś w dokumentach Androida powinno być więcej podkreślenia o tym problemie i można zachęcić do używania helpera singleton db.

Dzięki za to miłe pytanie i kontynuację.

 22
Author: Snicolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-22 20:29:21