[Android | Kotlin] Room

Deer·2021년 3월 29일
2
post-thumbnail

들어가기 전에


Room은 SQLite에 대한 추상 레이어를 제공하고 데이터베이스 엑세스를 지원하는 동시에 SQLite를 완벽히 활용한다. 쉽게 얘기해, SQLite에 있는 모든 기능을 쉽고 편리하게 쓸 수 있는 라이브러리이다.

Android 공식 문서를 보면, SQLite API 대신 Room을 사용할 것을 적극 권장한다.


Room의 구성 요소


안드로이드 Room의 주요 컴포넌트는 Entity, DAO, Database이다.

각 컴포넌트를 요약하면

  • Entity는 DB의 테이블이다. Class를 정의하고 Entity Annotation을 달아주면 해당 클래스의 프로퍼티들에 PK, UNIQUE 등의 제약조건을 달 수 있다.

  • DAO(Data Access Objects)는 테이블에 접근하여 쿼리를 실행시킬 수 있는 함수들을 지닌 클래스 혹은 인터페이스이다.

  • Database는 말 그대로 데이터베이스다. Database는 가상 클래스여야 하고 RoomDatabase를 상속해야 한다. Database는 Entity를 명시하여 테이블로 사용하고 Database가 DAO를 구현하여 제공한다.


Entity


Entity는 Database에서 테이블의 역할을 맡고있다.

다음과 같은 테이블이 있다고 가정하자.


MEMO

Field Type Null Key
memo_id INTEGER NO PK
title TEXT NO
content TEXT NO

이 테이블은 다음과 같은 Kotlin 클래스로 나타낼 수 있다.

@Entity(tableName = "memo")
data class Memo(
	@PrimaryKey()
	@ColumnInfo(name = "memo_id")
	val memo_id: Int,
	val title: String,
	val content: String
)

PrimaryKey Annotation에 autoGenerate를 true로 만들면 id에 값을 대입하지 않아도 자동으로 값이 들어간다.


DAO


DAO는 Data Access Object의 약자로 데이터베이스에 접근할 수 있는 객체이다.

DAO에는 DB에 접근할 수 있는 메서드를 정의한 인터페이스 또는 클래스로 다음과 같이 정의할 수 있다.

@Dao
interface MemoDao {
	@Insert
	suspend fun insertMemo(memo: Memo)
	
	@Delete
	suspend fun deleteMemo(memo: Memo)

	@Update
	suspend fun updateMemo(memo: Memo)

	@Query("SELECT * FROM memo WHERE memo_id == :id")
	suspend fun selectMemo(id: Int): List<Memo>

	@Query("DELETE FROM memo WHERE memo_id == :id")
	suspend fun deleteMemoById(id: Int)

	@Query("SELECT * FROM memo")
	suspend fun getAllMemo(): List<Memo>
}

내부 저장소에 접근한 결과를 비동기적으로 처리해야 하기 때문에, 각 함수 앞에 suspend를 붙여 비동기 함수로 만들어 준다.


Room Database


이제 DAO를 사용할 수 있는 객체를 만들 시간이다.

데이터베이스 객체는 RoomDatabase를 상속받는 가상 클래스이다.

@Database(entities = Memo::class, version = 1)
abstract class MemoDatabase : RoomDatabase() {
    abstract fun memoDao(): MemoDao

    companion object {
        private var instance: MemoDatabase? = null

        fun getInstance(context: Context): MemoDatabase? {
            if (instance == null) {
                synchronized(MemoDatabase::class) {
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        MemoDatabase::class.java, "memo.db"
                    ).build()
                }
            }
            return instance
        }
    }

}
  • 사용할 entity를 entities에 명시해 준다. 여러 Entity를 사용하는 상황일 때는, entities = [A::class, B::class]로 명시해 준다.
  • version는 데이터베이스 버전을 명시한다. 최초 버전은 1로, 데이터베이스 구조가 변경될 때마다 version을 올려준다.
  • 어디서든 접근할 수 있게 compain object를 이용해서 싱글톤 패턴으로 만들어준다.
  • 데이터베이스 구조가 변경될 시, version을 올려주는 동시에 migration을 add 해준다.
  • fallbackToDestructiveMigration()을 사용하면 migartion을 추가하지 않아도 데이터베이스의 변경이 적용된다. 단, 기존의 데이터베이스에 저장된 내용은 모두 날라간다.


사용법


모든 준비 과정이 끝났으므로 이제 사용할 수 있다.

현재 작성한 메모의 개수를 textView를 통해 작성해주자.

CoroutineScope(Dispatchers.Main).launch {
            val memoList = MemoDatabase.getInstance(this@MainActivity)?.memoDao()?.getAllMemo()
            val size = memoList?.size ?: 0
            findViewById<TextView>(R.id.text_view).text = size.toString()
        }



마무리


안드로이드 개발을 하다보면 서버 통신과 마찬가지로 내부 데이터베이스에 접근해야 할 일들이 매우 많을 것이다. Room Library를 활용하면 쉽고 편리하게 내부 DB에 접근하여 처리할 수 있다.

참고

  • 안드로이드 공식문서

https://developer.android.com/training/data-storage/room?hl=ko

profile
대구소프트웨어마이스터고등학교 5기 안드로이드 개발자

0개의 댓글