Eu iria mantê-lo aberto o tempo todo e fechá-lo em algum método de ciclo de vida, como onStop
ou onDestroy
. dessa forma, você pode verificar facilmente se o banco de dados já está em uso chamando isDbLockedByCurrentThread
ou isDbLockedByOtherThreads
no único SQLiteDatabase
objeto todas as vezes antes de usá-lo. isso evitará múltiplas manipulações no banco de dados e salvará seu aplicativo de um possível travamento
então, em seu singleton, você pode ter um método como este para obter seu único 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;
}
então, sempre que você quiser usar seu objeto auxiliar aberto, chame este método getter (certifique-se de que seja encadeado)
outro método em seu singleton pode ser (denominado CADA VEZ antes de tentar chamar o getter acima):
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
}
}
você pode querer fechar o banco de dados no singleton também:
public void finalize() throws Throwable {
if(null != mySingletonHelperField)
mySingletonHelperField.close();
if(null != db)
db.close();
super.finalize();
}
se os usuários de seu aplicativo têm a capacidade de criar muitas interações de banco de dados muito rapidamente, você deve usar algo como demonstrei acima. mas se houver interações mínimas com o banco de dados, eu não me preocuparia com isso, apenas criar e fechar o banco de dados todas as vezes.
A partir de agora, não há necessidade de verificar se o banco de dados está bloqueado por outro thread. Enquanto você usa o singleton SQLiteOpenHelper em cada thread, você está seguro. Da
isDbLockedByCurrentThread
documentação:isDbLockedByOtherThreads
está obsoleto desde o nível 16 da API.fonte
Em relação às perguntas:
Devemos dividir 'abrindo DB', 'abrindo uma conexão'. SQLiteOpenHelper.getWritableDatabase () fornece um banco de dados aberto. Mas não precisamos controlar as conexões, pois isso é feito internamente.
Sim, ele é. As conexões não param se as transações forem fechadas corretamente. Observe que seu banco de dados também será fechado automaticamente se o GC o finalizar.
Fechar a instância SQLiteDatabase não dá nada extraordinário, exceto fechar conexões, mas isso é ruim para o desenvolvedor se houver algumas conexões no momento. Além disso, após SQLiteDatabase.close (), SQLiteOpenHelper.getWritableDatabase () retornará uma nova instância.
Não, não há. Observe também que fechar o banco de dados em um momento e thread não relacionados, por exemplo, em Activity.onStop () pode fechar conexões ativas e deixar os dados em estado inconsistente.
fonte
O Android 8.1 tem um
SQLiteOpenHelper.setIdleConnectionTimeout(long)
método que:https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#setIdleConnectionTimeout(long)
fonte
Do ponto de vista do desempenho, a maneira ideal é manter uma única instância de SQLiteOpenHelper no nível do aplicativo. Abrir o banco de dados pode ser caro e é uma operação de bloqueio, portanto não deve ser feito no thread principal e / ou nos métodos de ciclo de vida da atividade.
O método setIdleConnectionTimeout () (introduzido no Android 8.1) pode ser usado para liberar RAM quando o banco de dados não é usado. Se o tempo limite de inatividade for definido, as conexões do banco de dados serão fechadas após um período de inatividade, ou seja, quando o banco de dados não foi acessado. As conexões serão reabertas de forma transparente para o aplicativo, quando uma nova consulta for executada.
Além disso, um aplicativo pode chamar releaseMemory () quando entra em segundo plano ou detecta pressão de memória, por exemplo, em onTrimMemory ()
fonte
Você também pode usar ContentProvider. Ele fará isso por você.
fonte
Crie seu próprio contexto de aplicativo e, em seguida, abra e feche o banco de dados a partir dele. Esse objeto também possui um método OnTerminate () que você pode usar para fechar a conexão. Ainda não tentei, mas parece uma abordagem melhor.
@binnyb: Não gosto de usar finalize () para fechar a conexão. Pode funcionar, mas pelo que entendi, escrever código em um método Java finalize () é uma má ideia.
fonte
onTerminate
não será chamado em um ambiente de produção - developer.android.com/reference/android/app/…