안드로이드에서 내장 데이터베이스에 저장하는 방법을 알아본다.
대표적인 저장 방법
- File(text..)
- SharedPreferences(key-value)
- RoomDB(관계형DB)
key-value 쌍으로 비교적 간단한 정보를 저장할 수 있는 방법인 SharedPreferences와 Room은 기기 내장 DB에 데이터베이스를 저장하기 위해 사용하는 라이브러리이다.
간단한 정보를 저장할 경우의 기준이란 무엇일까? 나는 저장할 데이터가 비즈니스의 core data 인지 아닌지 그리고 저장할 값이 단순히 key-value 값으로 저장하고 사용할 수 있는지에 따라 보통 구분 짓는다. 예를 들어 팝업창을 띄우는 경우 다시 보지 않기라는 값을 저장해야하는 상황이라면 이 값은 비즈니스의 core data도 아닐뿐더러 true, false 값으로 저장하고 사용할 수 있는 값이기에 SharedPreferences로 저장할 수 있다. SharedPreferences 개념부터 살펴보자.
1. Shared preferences
SharedPreferences 객체는 key-value 쌍이 포함된 파일을 가리키며 key-value 쌍을 읽고 쓸 수 있는 간단한 메서드를 제공한다.
key값은 String type, value는 기본적으로는 Boolean, String, Int 와 같은 기본적인 자료 구조만 가능하다. 하나의 key에 다중값을 담기 위해서는 String으로 여러 데이터를 표현하는 데이터 포맷인 JSON을 사용할 수 있다. 이는 외부 라이브러리인 GSON을 이용하여 변환 가능하다.
key값으로 "oauth"를 저장했고 value에 해당하는 값을 Gson() 라이브러리를 이용하여 OauthToken 객체인 token을 Json 형식으로 만들어 String 형태로 저장할 수 있다.
override fun saveToken(token: OauthToken) {
context.getSharedPreferences("token", Context.MODE_PRIVATE)
.edit()
.putString("oauth", Gson().toJson(token))
.apply()
}
또한 해당 값을 읽을 때도 SharedPreferences의 식별된 이름과 key 값을 이용, Gson()을 이용해 String화 되어있던 데이터를 다시 객체화시킨다.
override fun getToken(): OauthToken {
return Gson().fromJson(context.getSharedPreferences("token", Context.MODE_PRIVATE).getString("oauth", ""), OauthToken::class.java)
}
2. Room
Room은 Android 앱에서 SQLite 데이터베이스를 쉽게 사용할 수 있도록 Google 이 제공하는 라이브러리이다. Room은 SQLite 데이터베이스를 더 편리하게 사용할 수 있도록 추상화된 인터페이스를 제공하며 SQLite 기반이기에 SQL문을 사용하여 데이터의 흐름을 제어할 수 있다. Room을 사용하기 위해서는 크게 3가지의 구조를 아는 것이 필요하다. 데이터베이스의 구조를 나타내는 Entity, 데이터베이스의 접근과 조작을 위한 DAO(Data Access Object)등의 기능을 제공한다.
2-1. Entities
데이터베이스 내의 테이블을 의미한다. 각 Entity 클래스는 데이터베이스의 테이블을 대표하며 클래스의 멤버 변수들이 테이블의 컬럼과 매칭된다.
@Entity(tableName = "bookmark_table")
data class BookMarkEntity(
@PrimaryKey
val id: Int,
val name: String,
val isBookMarked: Boolean
)
2-2. Data Access Objects(DAO)
데이터에 접근할 수 있는 메서드를 정의해놓은 인터페이스이다. Room은 DAO를 사용하여 데이터를 삽입, 업데이트, 삭제, 조회 등의 작업을 수행한다.
@Dao
interface BookMarkDAO {
@Query("SELECT * FROM bookmark_table")
fun getAllBookmarks(): Single<List<BookMarkEntity>>
@Query("SELECT isBookMarked FROM bookmark_table WHERE id = :id")
fun getBookmarkById(id: Int) : Single<Boolean?>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveBookmark(data: BookMarkEntity): Completable
@Delete
fun deleteBookmark(data: BookMarkEntity): Completable
}
데이터베이스에 접근하는 함수(insert, update, delete)를 제공한다. 특정 조건을 붙이고 싶을 때는 SQL 문법으로 작성할 수도 있다. 예를 들어 bookmark_table 이라는 값 전부를 불러올 수 있고 bookmark_table의 같은 id 데이터의 isBookMarked 값을 가져올 수도 있다.
2-3. Room Database
실제 데이터베이스에 접근하는 클래스이다. Room Database는 데이터베이스를 관리하고, 앱 실행 시 데이터베이스 인스턴스를 생성하며 데이터베이스의 버전 업그레이드를 관리한다. 데이터베이스를 생성하고 관리하는 데이터베이스 객체 만들기 위해서 RoomDatabase 클래스를 확장한 추상 클래스를 만들어 줘야 한다. @Database 어노테이션으로 데이터베이스임을 표시한다. 또한 DAO 클래스의 인스턴스를 반환하는 추상 메서드를 정의해야 한다.
어노테이션안 entities 에는 데이터베이스에 저장할 entities 를 넣어주고 만약 entity의 구조를 변경해야하는 경우가 있다면 version을 업데이트 해줘야한다.
@Database(entities = [BookMarkEntity::class], version = 1)
abstract class BookMarkDatabase : RoomDatabase() {
abstract fun bookMarkDao(): bookMarkDAO
}
데이터 항목과 DAO, 데이터베이스 객체를 정의한 후에는 데이터베이스 인스턴스를 만들 수 있다. 문서에는 데이터베이스 객체를 인스턴스화할 때 많은 리소스의 소비로 싱글톤 구현을 권장하고 있다.
참고: 앱이 단일 프로세스에서 실행되면 AppDatabase 객체를 인스턴스화할 때 싱글톤 디자인 패턴을 따라야 합니다. 각
RoomDatabase 인스턴스는 리소스를 상당히 많이 소비하며 단일 프로세스 내에서 여러 인스턴스에 액세스해야 하는 경우는 거의 없습니다.
companion object {
private var instance: BookMarkEntity? = null
@Synchronized
fun getInstance(context: Context): BookMarkEntity? {
if (instance == null)
synchronized(BookMarkEntity::class) {
instance = Room.databaseBuilder(
context.applicationContext,
BookMarkEntity::class.java,
"bookMark.db"
)
.build()
}
return instance
}
fun destroyInstance() {
instance = null
}
}
사용은 AppDatabase의 추상 메서드를 사용하여 DAO 인스턴스를 가져올 수 있다. 결과적으로 DAO 인스턴스의 메서드를 사용하여 데이터베이스와 상호작용 할 수 있다.
val databaseModule = module {
single { MarketStatusDatabase.getInstance(androidContext()) }
}
class BookMarkRepositoryImpl(
private val marketDataBase: MarketStatusDatabase
): MarketRepository {
override fun getBookMarkedList(): Single<List<MarketStatusDatabaseEntity>> {
return marketDataBase.marketStatusDao().getAllBookmarks()
}
}
이렇게 인스턴스화된 데이터베이스는 안드로이드 스튜디오내 Database Inspector에서 테이블을 볼 수 있다.
'🐸 Android' 카테고리의 다른 글
[Android] Fragment의 LifeCycle과 viewLifecycleOwner 뜯어보기 (0) | 2023.08.13 |
---|---|
[Android] 안드로이드의 Process와 Thread (0) | 2023.08.09 |
[Android] 안드로이드에서 Deep Links 처리하기 (0) | 2023.07.04 |
[Android] Fastlane으로 앱스토어 자동 배포하기 (0) | 2023.07.04 |
[Android] 앱 삭제 후 데이터가 남아있는 문제 (0) | 2023.07.04 |