[Android] AAC - Room

ENAN·2021년 6월 25일
0

Rooom이란?

Room은 SQLite의 추상 레이어를 제공해 주어 DB에 편하게 접근할 수 있도록 해주는 ORM Library이다. JetPack, 그 안에서도 AAC 안에 속해있는 라이브러리 중 하나다.

SQLite에 비해 Room을 사용했을 때 얻을 수 있는 이점이 많다.보일러 플레이트 코드를 줄일 수 있다는 점부터, 컴파일 타임에 유효성 검사를 할 수 있고, schema가 변경되었을 때도 자동으로 업데이트가 되며, LiveData 등과 함께 사용해 데이터를 Observation 할 수 있다는 점 등 장점이 많다. 현재 Google은 SQLite 대신 room을 사용하기를 적극적으로 권장하고 있다.

사용 방법

1. dependency 추가

Room 을 입력하고 alt + Enter를 누르면 dependency를 자동으로 추가할 수 있다.
(하지만 어차피 annotation 처리를 위해 gradle에 아래 내용을 추가해주어야 한다)

// kapt plugin 추가
apply plugin: 'kotlin-kapt'

dependencies {
    implementation "androidx.room:room-runtime:$room_version"
    // annotationProcessor 대신 kapt
    kapt "androidx.room:room-compiler:$room_version"
}

2. Entity 정의

class 위에 @Entity 어노테이션을 붙여주어 Room 에서 관리하는 Entity로 인식시킨다.
멤버 변수에 @PrimaryKey 어노테이션을 붙여주면 primary key로 지정할 수 있다.

이 때, autoGenerate = True 옵션으로 키값을 자동으로 증가시키게 할 수 있다.

@Entity
data class Todo(var title:String) {
    @PrimaryKey(autoGenerate = true) var id:Int = 0
}

3. Dao 작성

@Dao 어노테이션으로 Dao interface를 정의한다.
(DAO란 data access object로, Data에 직접 access하는 역할의 객체를 말한다. 실질적으로 db와의 정보 전달은 이 dao를 통해서만 이루어질 것이다)

@Query 어노테이션으로 직접 쿼리를 실행할 수 있고, 기본적으로 @Insert, @Update, @Delete 와 같은 어노테이션을 사용할 수 있다. 전달받은 객체를 insert하거나, 전달받은 객체와 primary key가 일치하는 객체를 업데이트 혹은 삭제한다.

아래 getAll 함수에서 반환형을 잘 보면 List<Todo>가 아닌 LiveData<List<Todo>>라는 것이 보이는데, LiveData와 연계하여 아래와 같이 사용할 수 있으며 놀랍게도 observing하고 있으면 db의 값이 변경될 때 마다 신호를 보내줄 수 있다! 다음에 LiveData를 다루면서 자세히 적어 보겠다.

@Dao
interface TodoDao {
    @Query("SELECT * FROM Todo")
    fun getAll(): LiveData<List<Todo>>

    @Insert
    suspend fun insert(todo: Todo)

    @Update
    suspend fun update(todo: Todo)

    @Delete
    suspend fun delete(todo: Todo)
}

4. AppDatabase 작성

실제로 사용하는 곳에서 호출하는 시작점이 될 객체다.
entities에 사용하는 entity들을 적어주고, Dao 객체를 가져올 수 있게 함수를 정의한다.

@Database(entities = [Todo::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun todoDao(): TodoDao
}

5. 호출

먼저 db객체를 생성한다. (공식 문서에서는 액티비티나 뷰모델 마다 생성하지 않고 싱글톤으로 관리하는 것을 권장한다)

그리고 db객체에서 원하는 dao를 호출한 후, dao의 함수를 호출한다.

    private val db = Room.databaseBuilder(
            application,
            AppDatabase::class.java,
            "test_db"
    )
//            .allowMainThreadQueries() // 비동기 처리 하기 전 임시로 사용
            .build()

    fun getAll(): LiveData<List<Todo>> {
        return db.todoDao().getAll()
    }

    fun insert(todo: String) {
        viewModelScope.launch(Dispatchers.IO) { // 코루틴을 사용한 비동기 처리
            db.todoDao().insert(Todo(todo))
        }
    }

주의점

DB는 main thread에서 동작시키려 하면 오류가 난다! 임시로 allowMainThreadQueries() 을 사용해 메인 쓰레드에서 돌아가게 허용해주거나 coroutine을 사용해서 IO thread에서 호출하도록 하자!

+ vs Realm?

전에 진행하던 프로젝트(Roadline)에서는 Realm 데이터베이스를 사용했었다. 그때는 room에 대해 잘 몰랐기도 하고, '좋다고들 하니 써 보자!' 하는 생각이었는데 Room을 공부하면서 Realm과 어떤 차이가 있는지 궁금해졌다.

길어질 것 같아 언제 한번 정리해서 적도록 하겠습니다!

profile
여정이 곧 보상

0개의 댓글