2010-12-29 25 views
87

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?Android SQLite DB Cuándo cerrar

Gracias!

Respuesta

59

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 al isDbLockedByCurrentThread o isDbLockedByOtherThreads en el único objeto SQLiteDatabase cada vez que lo use. esto evitará múltiples manipulaciones a la base de datos y guardar su solicitud de un fallo potencial

por lo que en su único, que podría tener un método como este para obtener su única SQLiteOpenHelper objeto:

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

manera siempre que lo desee utilizar su objeto ayudante abierta, llamar a este método getter (asegúrese de que está enroscado)

otro método en su Singleton se puede (llamado cada vez que antes de intentar llamar al captador de arriba):

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 
    } 
} 

es posible que desee cerrar la base de datos en el singleton así:

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

si los usuarios de la aplicación tienen la capacidad de crear muchas interacciones de bases de datos muy rápidamente, usted 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.

+27

+1 yodo como si fuera –

+0

Podría acelerar el acceso a la base de datos por un factor de 2 con este enfoque (mantener la base de datos abierta), gracias –

+2

Spinning es una técnica muy mala. Ver mi respuesta a continuación. – mixel

-8

Crea tu propio contexto de aplicación, luego abre y cierra 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 finalizar() 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.

+0

No desea confiar en finalizar porque nunca se sabe cuándo se va a llamar. Un objeto puede permanecer en el limbo hasta que el GC decida limpiarlo, y solo entonces se llamará a finalize(). Es por eso que es inútil. La forma correcta de hacerlo es tener un método que se invoca cuando el objeto ya no se usa (independientemente de que se haya recogido basura o no), y eso es exactamente lo que ocurre enTerminate(). – erwan

+4

Los documentos dicen claramente que 'onTerminate' no se llamará en un entorno de producción: http://developer.android.com/reference/android/app/Application.html#onTerminate() – Eliezer

0

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

18

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

El nombre de este método proviene de una época en la que tiene una activa conexión con la base de datos significa que el hilo se mantiene un bloqueo real en la base de datos. Hoy en día, ya no existe un verdadero "bloqueo 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.

9

En cuanto a las preguntas:

Mi gestor de base de datos es un conjunto unitario y en este momento se abre una conexión con 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é abierto?

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 es necesario.

Cerrar la instancia de SQLiteDatabase no ofrece nada tremendo, excepto el cierre de las conexiones, pero este es un problema del 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 en dejarlo abierto todo el tiempo?

No, no lo hay. Tenga en cuenta también que cerrar el DB en un momento no relacionado e hilo, p. en Activity.onStop() puede cerrar las conexiones activas y dejar los datos en estado incoherente.

0

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

setIdleConnectionTimeout() método (introducido en Android 8.1) se puede utilizar para liberar RAM cuando la base de datos no se utiliza. 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 al releaseMemory() cuando se pone en segundo plano o detecta la presión de la memoria, p. en onTrimMemory()

Cuestiones relacionadas