Uso del patrón de diseño Singleton para SQLiteDatabase

Soy bastante novato en Android, y estoy trabajando en una aplicación simple para obtener algo de experiencia básica. Mi aplicación es bastante simple y consiste, entre otras cosas, en un receptor de difusión y algunas actividades. Ambos componentes utilizan una sola base de datos, por lo que, en teoría, podría suceder que ambos intenten acceder a la base de datos simultáneamente.

Actualmente, simplemente estoy instanciando el objeto db (que es una clase de SQLite db helper) cada vez que lo necesito, y realizando las operaciones necesarias: consulta, inserción, etc.

De lo que he estado leyendo aquí y en algunos otros documentos, esto tiene el problema de obtener una excepción “db locked” en caso de que se acceda a la base de datos simultáneamente, por lo que un mejor enfoque sería tener una única instancia de este objeto db para que todo los componentes utilizan la misma conexión db en todo momento.

¿Es correcto el razonamiento anterior? ¿Sería un singleton una buena solución para esto? Sé que algunos puristas pueden argumentar en contra, pero tenga en cuenta que esta es una aplicación bastante simple, así que me puedo permitir hacer cosas que no haría en otros casos.

De lo contrario, ¿cuál sería una mejor opción? He leído sobre el uso del proveedor de contenido, pero sería demasiado para esto, además de que no estoy interesado en compartir los datos con otras actividades. De hecho, he leído esta publicación y la encontré bastante útil.

Haga clic aquí para ver la publicación de mi blog sobre este tema.


Aquí hay un código de muestra que ilustra tres enfoques posibles. Estos permitirán el acceso a la base de datos en toda la aplicación.

Método n. ° 1: tener `SQLiteOpenHelper` como miembro de datos estáticos

Esta no es la implementación completa, pero debería darle una buena idea sobre cómo diseñar correctamente la clase DatabaseHelper . El método de fábrica estático garantiza que solo exista una instancia de DatabaseHelper en cualquier momento.

 /** * 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; } } 

Método n. ° 2: abstrae la base de datos SQLite con un `ContentProvider`

Este es el enfoque que sugeriría. Por un lado, la nueva clase CursorLoader requiere ContentProvider s, así que si quieres una actividad o fragmento para implementar LoaderManager.LoaderCallbacks con un CursorLoader (que sugiero que aproveches, ¡es mágico!), Necesitarás implementar un ContentProvider para su aplicación. Además, no necesita preocuparse por crear una base de datos de Singleton con ContentProviders. Simplemente llame a getContentResolver() desde la actividad y el sistema se encargará de todo por usted (en otras palabras, no es necesario diseñar un patrón de Singleton para evitar que se creen varias instancias).

¡Espero que esto ayude!

Nunca leí acerca de usar un singleton para acceder a un db en Android. ¿Le importaría proporcionar un enlace sobre eso?

En mis aplicaciones, utilizo objetos dbhelper simples, no simples, estaba pensando que este es más el trabajo del motor sql para asegurar que db no esté bloqueado, no es el trabajo de sus clases de Android, y funciona bastante bien para mi aplicación más grande que es de tamaño mediano.

Actualización n. ° 1: mirando la referencia que proporcionó, parece que el problema no es utilizar instancias diferentes de un dbhelper . Incluso una sola instancia podría tener problemas para acceder a las bases de datos: el problema proviene de un acceso simultáneo. Por lo tanto, la única forma de garantizar un acceso adecuado a la base de datos mediante diferentes subprocesos es usar mecanismos simples de sincronización de subprocesos (métodos o bloques synchronized ), y casi nada con el uso de un singleton.

Actualización n. ° 2: el segundo enlace que proporciona muestra claramente que se necesitan objetos singleton dbhelper en el caso de varios hilos que escriben simultáneamente en un archivo db. Esto puede suceder si realiza operaciones sql (inserciones / actualizaciones / eliminaciones) de AsyncTasks, por ejemplo. En ese caso, un objeto singleton dbhelper simplemente pondría todas las operaciones sql en algún tipo de canalización y las ejecutaría en orden.

Esta solución podría ser más fácil de implementar que utilizar una sincronización de subprocesos adecuada utilizando métodos sincronizados en Java. De hecho, creo que debería haber más énfasis en algún lugar de los documentos de android sobre este problema y podría alentarse el uso de un db de ayuda singleton.

Gracias por esta buena pregunta y los seguimientos.