답변:
나는 그것을 항상 열어두고 onStop
또는 같은 수명주기 방법으로 닫을 것입니다 onDestroy
. 이렇게하면 사용하기 전에 매번 isDbLockedByCurrentThread
또는 isDbLockedByOtherThreads
단일 SQLiteDatabase
객체 를 호출하여 데이터베이스가 이미 사용 중인지 쉽게 확인할 수 있습니다 . 이것은 데이터베이스에 대한 다중 조작을 방지하고 잠재적 인 충돌로부터 애플리케이션을 저장합니다.
따라서 싱글 톤에서 단일 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;
}
따라서 열린 도우미 개체를 사용하고 싶을 때마다이 getter 메서드를 호출하십시오 (스레딩되었는지 확인하십시오).
싱글 톤의 다른 메소드는 다음과 같습니다 (위의 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
}
}
싱글 톤에서 데이터베이스를 닫고 싶을 수도 있습니다.
public void finalize() throws Throwable {
if(null != mySingletonHelperField)
mySingletonHelperField.close();
if(null != db)
db.close();
super.finalize();
}
애플리케이션 사용자가 많은 데이터베이스 상호 작용을 매우 빠르게 생성 할 수있는 능력이 있다면 위에서 설명한 것과 같은 것을 사용해야합니다. 그러나 최소한의 데이터베이스 상호 작용이 있다면 걱정하지 않고 매번 데이터베이스를 만들고 닫습니다.
현재로서는 데이터베이스가 다른 스레드에 의해 잠겼는지 확인할 필요가 없습니다. 모든 스레드에서 단일 SQLiteOpenHelper를 사용하는 동안 안전합니다. 에서 isDbLockedByCurrentThread
문서 :
이 메소드의 이름은 데이터베이스에 대한 활성 연결이 스레드가 데이터베이스에 대한 실제 잠금을 보유하고 있음을 의미 할 때 유래되었습니다. 요즘에는 특정 작업을 수행하기 위해 데이터베이스 연결을 획득 할 수없는 경우 스레드가 차단 될 수 있지만 더 이상 진정한 "데이터베이스 잠금"이 없습니다.
isDbLockedByOtherThreads
API 레벨 16부터 더 이상 사용되지 않습니다.
질문에 관하여 :
내 데이터베이스 관리자는 싱글 톤이며 현재 초기화 될 때 데이터베이스에 대한 연결을 엽니 다.
'DB 개설'과 '연결 개설'을 나누어야합니다. SQLiteOpenHelper.getWritableDatabase ()는 열린 DB를 제공합니다. 그러나 내부적으로 수행되므로 연결을 제어 할 필요가 없습니다.
누군가가 내 클래스를 호출하여 데이터베이스 작업을 할 때 이미 열려 있도록 데이터베이스를 항상 열어 두는 것이 안전합니까?
네, 그렇습니다. 트랜잭션이 제대로 닫히면 연결이 중단되지 않습니다. GC가 완료하면 DB도 자동으로 닫힙니다.
또는 각 액세스가 필요하기 전과 후에 데이터베이스를 열고 닫아야합니다.
SQLiteDatabase 인스턴스를 닫는 것은 연결을 닫는 것 외에는 아무 것도 제공하지 않지만 현재 연결이 있으면 개발자에게 나쁜 일입니다. 또한 SQLiteDatabase.close () 이후 SQLiteOpenHelper.getWritableDatabase ()는 새 인스턴스를 반환합니다.
계속 열어두면 해가 되는가?
아니, 없습니다. 또한 Activity.onStop ()과 같이 관련없는 순간에 DB를 닫고 스레드를 닫으면 활성 연결이 닫히고 데이터가 일관성없는 상태로 남을 수 있습니다.
Android 8.1에는 다음과 같은 SQLiteOpenHelper.setIdleConnectionTimeout(long)
방법이 있습니다.
SQLite 연결이 풀에서 닫히고 제거되기 전에 유휴 상태가 될 수있는 최대 시간 (밀리 초)을 설정합니다.
성능 관점에서 최적의 방법은 애플리케이션 수준에서 SQLiteOpenHelper의 단일 인스턴스를 유지하는 것입니다. 데이터베이스를 여는 것은 비용이 많이 들고 차단 작업이므로 주 스레드 및 / 또는 활동 수명주기 메서드에서 수행해서는 안됩니다.
setIdleConnectionTimeout () 메서드 (Android 8.1에 도입 됨)를 사용하여 데이터베이스를 사용하지 않을 때 RAM을 확보 할 수 있습니다. 유휴 시간 제한이 설정되어 있으면 데이터베이스 연결이 일정 시간 동안 사용하지 않으면 (예 : 데이터베이스에 액세스하지 않은 경우) 닫힙니다. 새 쿼리가 실행되면 연결이 앱에 투명하게 다시 열립니다.
또한 앱 이 백그라운드로 들어가거나 메모리 부족을 감지 할 때 releaseMemory ()를 호출 할 수 있습니다 ( 예 : onTrimMemory ()).
고유 한 응용 프로그램 컨텍스트를 만든 다음 거기에서 데이터베이스를 열고 닫습니다. 이 개체에는 연결을 닫는 데 사용할 수있는 OnTerminate () 메서드도 있습니다. 나는 아직 시도하지 않았지만 더 나은 접근 방식으로 보입니다.
@binnyb : 나는 finalize ()를 사용하여 연결을 닫는 것을 좋아하지 않습니다. 작동 할 수도 있지만 Java finalize () 메서드에서 코드를 작성하는 것을 이해하는 것은 나쁜 생각입니다.
onTerminate
생산 환경에서 호출되지 않습니다 - developer.android.com/reference/android/app/...