Android SQLite DB Cuándo cerrar

Estoy trabajando con una base de datos SQLite en Android. Mi administrador de bases de datos es un singleton y ahora abre una conexión a la base de datos cuando se inicializa. ¿Es seguro dejar la base de datos abierta todo el tiempo para que cuando alguien llama a mi clase para trabajar con la base de datos ya esté abierta? O debería abrir y cerrar la base de datos antes y después de cada acceso. ¿Hay algún daño al dejarlo abierto todo el tiempo?

¡Gracias!

Lo mantendría abierto todo el tiempo, y lo cerraría en algún método de ciclo de vida como onStop o onDestroy . de esta forma, puede verificar fácilmente si la base de datos ya está en uso llamando a isDbLockedByCurrentThread o isDbLockedByOtherThreads en el único objeto SQLiteDatabase cada vez antes de usarlo. esto evitará múltiples manipulaciones en la base de datos y guardará su aplicación de una posible falla

entonces en tu singleton, podrías tener un método como este para obtener tu único objeto SQLiteOpenHelper :

 private SQLiteDatabase db; private MyDBOpenHelper mySingletonHelperField; public MyDBOpenHelper getDbHelper() { db = mySingletonHelperField.getDatabase();//returns the already created database object in my MyDBOpenHelper class(which extends `SQLiteOpenHelper`) while(db.isDbLockedByCurrentThread() || db.isDbLockedByOtherThreads()) { //db is locked, keep looping } return mySingletonHelperField; } 

así que cada vez que quiera usar su objeto auxiliar abierto, llame a este método getter (asegúrese de que esté enhebrado)

otro método en su singleton puede ser (llamado CADA VEZ antes de intentar llamar al captador anterior):

 public void setDbHelper(MyDBOpenHelper mySingletonHelperField) { if(null == this.mySingletonHelperField) { this.mySingletonHelperField = mySingletonHelperField; this.mySingletonHelperField.setDb(this.mySingletonHelperField.getWritableDatabase());//creates and sets the database object in the MyDBOpenHelper class } } 

También puede cerrar la base de datos en singleton:

 public void finalize() throws Throwable { if(null != mySingletonHelperField) mySingletonHelperField.close(); if(null != db) db.close(); super.finalize(); } 

si los usuarios de su aplicación tienen la capacidad de crear muchas interacciones de bases de datos muy rápidamente, debe usar algo como lo he demostrado anteriormente. pero si hay interacciones mínimas en la base de datos, no me preocuparía, y solo crearía y cerraría la base de datos todo el tiempo.

A partir de ahora no hay necesidad de verificar si la base de datos está bloqueada por otro hilo. Mientras usa singlete SQLiteOpenHelper en cada hilo, está a salvo. De la documentación de isDbLockedByCurrentThread :

El nombre de este método proviene de un momento en que tener una conexión activa a la base de datos significaba que el hilo tenía un locking real en la base de datos. Hoy en día, ya no existe un verdadero “locking de base de datos”, aunque los hilos pueden bloquearse si no pueden adquirir una conexión de base de datos para realizar una operación en particular.

isDbLockedByOtherThreads está en desuso desde API nivel 16.

En cuanto a las preguntas:

Mi administrador de bases de datos es un singleton y ahora abre una conexión a la base de datos cuando se inicializa.

Deberíamos dividir ‘abrir DB’, ‘abrir una conexión’. SQLiteOpenHelper.getWritableDatabase () da una base de datos abierta. Pero no tenemos que controlar las conexiones como se hace internamente.

¿Es seguro dejar la base de datos abierta todo el tiempo para que cuando alguien llama a mi clase para trabajar con la base de datos ya esté abierta?

Sí lo es. Las conexiones no se bloquean si las transacciones se cierran correctamente. Tenga en cuenta que su DB también se cerrará automáticamente si GC lo finaliza.

O debería abrir y cerrar la base de datos antes y después de cada acceso.

Cerrar la instancia de SQLiteDatabase no ofrece nada tremendo excepto cerrar conexiones, pero este es un problema para el desarrollador si hay algunas conexiones en este momento. Además, después de SQLiteDatabase.close (), SQLiteOpenHelper.getWritableDatabase () devolverá una nueva instancia.

¿Hay algún daño al dejarlo abierto todo el tiempo?

No, no hay. Tenga en cuenta también que el cierre de la base de datos en un momento no relacionado e hilo, por ejemplo, en Activity.onStop () podría cerrar las conexiones activas y dejar los datos en estado incoherente.

Android 8.1 tiene un SQLiteOpenHelper.setIdleConnectionTimeout(long) que:

Establece el número máximo de milisegundos que permite que la conexión SQLite esté inactiva antes de que se cierre y elimine del grupo.

https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#setIdleConnectionTimeout(long)

También puede usar ContentProvider. Hará esto por ti.

Desde la perspectiva del rendimiento, la forma óptima es mantener una única instancia de SQLiteOpenHelper en el nivel de la aplicación. Abrir la base de datos puede ser costoso y es una operación de locking, por lo que no debe hacerse en el hilo principal y / o en los métodos del ciclo de vida de la actividad.

El método setIdleConnectionTimeout () (introducido en Android 8.1) se puede usar para liberar RAM cuando la base de datos no se usa. Si se establece el tiempo de espera inactivo, las conexiones de la base de datos se cerrarán después de un período de inactividad, es decir, cuando no se accedió a la base de datos. Las conexiones se volverán a abrir de forma transparente a la aplicación cuando se ejecute una nueva consulta.

Además de eso, una aplicación puede llamar a releaseMemory () cuando se pone en segundo plano o detecta la presión de la memoria, por ejemplo, enTrimMemory ()

Cree su propio contexto de Aplicación, luego abra y cierre la base de datos desde allí. Ese objeto también tiene un método OnTerminate () que puede usar para cerrar la conexión. No lo he intentado todavía, pero parece un mejor enfoque.

@binnyb: no me gusta usar finalize () para cerrar la conexión. Podría funcionar, pero por lo que entiendo escribir código en un método Java finalize () es una mala idea.