Pozostawiłbym go otwarty przez cały czas i zamknąłbym go w jakiejś metodzie cyklu życia, takiej jak onStop
lub onDestroy
. w ten sposób możesz łatwo sprawdzić, czy baza danych jest już używana, dzwoniąc isDbLockedByCurrentThread
lub isDbLockedByOtherThreads
pojedynczoSQLiteDatabase
obiektu za każdym razem przed użyciem. zapobiegnie to wielu manipulacjom w bazie danych i uchroni aplikację przed potencjalną awarią
więc w swoim singletonie możesz mieć taką metodę, aby pobrać pojedynczy SQLiteOpenHelper
obiekt:
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;
}
więc kiedy chcesz użyć swojego otwartego obiektu pomocniczego, wywołaj tę metodę pobierającą (upewnij się, że jest podzielona na wątki)
inną metodą w twoim singletonie może być (nazywana KAŻDYM RAZEM zanim spróbujesz wywołać powyższy getter):
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
}
}
możesz chcieć zamknąć bazę danych również w singletonie:
public void finalize() throws Throwable {
if(null != mySingletonHelperField)
mySingletonHelperField.close();
if(null != db)
db.close();
super.finalize();
}
jeśli użytkownicy Twojej aplikacji mają możliwość bardzo szybkiego tworzenia wielu interakcji z bazą danych, powinieneś użyć czegoś, co pokazałem powyżej. ale jeśli interakcje z bazą danych są minimalne, nie martwiłbym się tym i po prostu tworzyłem i zamykałem bazę danych za każdym razem.
Na razie nie ma potrzeby sprawdzania, czy baza danych jest zablokowana przez inny wątek. Używając singletona SQLiteOpenHelper w każdym wątku, jesteś bezpieczny. Z
isDbLockedByCurrentThread
dokumentacji:isDbLockedByOtherThreads
jest przestarzałe od 16 poziomu interfejsu API.źródło
Odnośnie pytań:
Powinniśmy podzielić „otwieranie bazy danych”, „otwieranie połączenia”. SQLiteOpenHelper.getWritableDatabase () daje otwartą bazę danych. Ale nie musimy kontrolować połączeń, ponieważ odbywa się to wewnętrznie.
Tak to jest. Połączenia nie zawieszają się, jeśli transakcje są poprawnie zamknięte. Zauważ, że twoja baza danych zostanie również automatycznie zamknięta, jeśli GC ją sfinalizuje.
Zamknięcie instancji SQLiteDatabase nie daje nic wielkiego poza zamykaniem połączeń, ale jest to zła sytuacja programisty, jeśli w tej chwili są jakieś połączenia. Ponadto po SQLiteDatabase.close () SQLiteOpenHelper.getWritableDatabase () zwróci nową instancję.
Nie, nie ma. Zauważ również, że zamknięcie bazy danych w niepowiązanym momencie i wątku, np. W Activity.onStop () może zamknąć aktywne połączenia i pozostawić dane w stanie niespójnym.
źródło
Android 8.1 ma
SQLiteOpenHelper.setIdleConnectionTimeout(long)
metodę, która:https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#setIdleConnectionTimeout(long)
źródło
Z punktu widzenia wydajności optymalnym sposobem jest utrzymanie pojedynczego wystąpienia SQLiteOpenHelper na poziomie aplikacji. Otwieranie bazy danych może być kosztowne i jest operacją blokującą, więc nie powinno się tego robić w głównym wątku i / lub w metodach cyklu życia działania.
setIdleConnectionTimeout () (wprowadzona w systemie Android 8.1) może służyć do zwolnienia pamięci RAM, gdy baza danych nie jest używana. Jeśli ustawiony jest limit czasu bezczynności, połączenia z bazą danych zostaną zamknięte po okresie bezczynności, tj. Gdy nie uzyskano dostępu do bazy danych. Połączenia zostaną ponownie otwarte w trybie przezroczystym dla aplikacji, gdy zostanie wykonane nowe zapytanie.
Oprócz tego aplikacja może wywołać funkcję releaseMemory (), gdy przechodzi w tło lub wykryje obciążenie pamięci, np. W onTrimMemory ()
źródło
Możesz także używać ContentProvider. Zrobi to za Ciebie.
źródło
Utwórz własny kontekst aplikacji, a następnie otwórz i zamknij bazę danych z tego miejsca. Ten obiekt ma również metodę OnTerminate (), której można użyć do zamknięcia połączenia. Jeszcze tego nie próbowałem, ale wydaje się, że jest to lepsze podejście.
@binnyb: Nie lubię używać finalize () do zamykania połączenia. Może działać, ale z tego, co rozumiem, pisanie kodu w metodzie finalize () w języku Java to zły pomysł.
źródło
onTerminate
nie zostanie wywołane w środowisku produkcyjnym - developer.android.com/reference/android/app/ ...