본문 바로가기

Android/꼭 공부해야 할 라이브러리

Room 을 사용해 데이터를 관리하자! with 사용법과 예제

안녕하세요? 닉네임간편입니다. 이번 시간에는 Room 라이브러리를 사용하겠습니다.

1. 개요

ORM은 객체와 관계형 데이터베이스의 데이터를 매핑하고 변환하는 기술로 복잡한 쿼리를 잘 몰라도 코드만으로 데이터베이스의 모든 것을 컨트롤할 수 있도록 도와줍니다.

안드로이드는 SQLite를 코드 관점에서 접근할 수 있도록 ORM 라이브러리인 Room을 제공합니다.

안드로이드 스튜디오는 SQLite보다 Room을 사용하는 것을 굉장히 권장하기 때문에, 저도 Room을 자주 사용합니다.

2. 준비

Room 라이브러리를 사용하기 전 준비가 필요합니다.

1) build.gradle(app) 파일에 아래 플러그인을 추가합니다.

plugins{
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt' // 이 부분 추가
id 'kotlin-parcelize'
}

2) 같은 파일 아래에 android 블록에 다음과 같은 코드를 추가하여 뷰 바인딩을 사용할 수 있도록 설정합니다.

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"
		...

	buildFeatures{
		viewBinding true
	}
...
}

3) dependencies 블록 안에 아래 코드를 추가합니다.

def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"

버전 정보는 달라질 수 있으니 개발자 문서에서 확인해야 합니다.

https://developer.android.com/jetpack/androidx/releases/room?hl=ko

 

Room  |  Android 개발자  |  Android Developers

Room Room 지속성 라이브러리는 SQLite에 추상화 레이어를 제공하여 SQLite를 완벽히 활용하면서 더 견고한 데이터베이스 액세스를 가능하게 합니다. 최근 업데이트 현재 안정화 버전 다음 버전 후보

developer.android.com

Room은 빠른 처리 속도를 위해 어노테이션 프로세서를 사용하는데, 코틀린에서는 이를 대신해서 kapt를 사용합니다. kapt를 사용하기 위해서 위 코드 중 'kapt'로 시작하는 코드를 추가하였습니다.

이제 우측 상단에 [Sync Now]를 클릭하여 변경된 사항을 적용하면 됩니다.

3. 사용법 - Room에 사용될 클래스 만들기

먼저 Room에 사용될 클래스를 만들어줍니다.

@Entity(tableName = "room_basket")
class RoomBasket {
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo
    var no: Long? = null

    @ColumnInfo
    var title: String = ""

    @ColumnInfo
    var price: Long = 0

    @ColumnInfo
    var menumore: String? = null

    @ColumnInfo
    var totalquantity: Long = 0

    constructor(title: String, price: Long, menumore: String?, totalquantity: Long) {
        this.title = title
        this.price = price
        this.menumore = menumore
        this.totalquantity = totalquantity
    }
}

1) @Entity

Room 라이브러리는 이 어노테이션이 적용된 클래스를 찾아 테이블로 변환합니다.

이때 클래스 이름과 테이블 이름을 다르게 하고 싶다면 위 코드처럼 (tableName = [원하는 이름])으로 설정하면 됩니다.

2) @ColumnInfo

변수 이름 위에 이 어노테이션을 작성하면 테이블의 컬럼으로 사용됩니다.

만일 변수 이름과 칼럼 이름을 다르게 하고 싶다면 (name = [칼럼 이름])으로 설정하면 됩니다.

3) @PrimaryKey

기본키를 설정합니다.

이때 자동으로 증가하도록 만들기 위해선 (autoGenerate = true)로 설정하면 됩니다.

4) @Ignore

여기선 사용되지 않았지만 만일 변수를 칼럼으로 사용하고 싶지 않다면 이 어노테이션을 설정하면 됩니다.

4. 사용법 - DAO

Room은 데이터베이스에 읽고 쓰는 메서드를 인터페이스 형태로 설계하고 사용합니다. 코드 없이 이름만 명시하는 형태로 인터페이스를 만들면 Room이 나머지 코드를 자동 생성합니다.

이때 DAO란 데이터베이스에 접근해서 DML 쿼리(SELECT, INSERT, UPDATE, DELETE)를 실행하는 메서드의 모음입니다.

이 인터페이스를 정의하기 위해선 @Dao를 적용하면 됩니다.

@Dao
interface RoomBasketDao {
@Query("select * from room_basket6")
    fun getAll(): List<RoomBasket>

    @Query("select * from room_basket6 where title = :inputTitle ")
    fun getTitleList(inputTitle: String) : List<RoomBasket>

    @Insert(onConflict = REPLACE)
    fun insert(basket: RoomBasket)

    @Delete
    fun delete(basket: RoomBasket)

    @Query("delete from room_basket6")
    fun deleteAll()

    @Query("update room_basket6 set totalquantity = :quantity where num = :number")
    fun update(quantity: Long, number: Long?)

    @Query("update room_basket6 set totalquantity = :quantity, totalprice = :price where num = :number")
    fun updateTQ(quantity: Long, price: Long, number: Long?)

}

1) @Query

Room은 다른 ORM 툴과는 다르게 조회를 하는 select 쿼리를 직접 작성하도록 설계되어 있습니다.

따라서 위 코드처럼 만들어줍니다.

2) @Insert

추가하는 메서드를 만들어줍니다.

이때 (onConflict = REPLACE)를 설정하면 동일한 키를 가진 값이 입력되었을 때 UPDATE 쿼리로 실행됩니다.

3) @Delete

제거하는 메서드를 만들어줍니다.

그 이외에는 기존 SQLite 구문처럼 사용하면 됩니다.

5. 사용법 - RoomHelper

SQLiteOpenHelper를 상속받아서 구현했던 것처럼 Room도 유사한 구조로 사용할 수 있습니다.

Room은 RoomDatabase를 제공하는데, RoomDatabase를 상속받아 클래스를 생성하면 됩니다.

이때 추상 클래스로 생성해야 합니다.

@Database(entities =arrayOf(RoomBasket::class), version = 1, exportSchema = false)
abstract class RoomHelper : RoomDatabase() {
    abstract fun roomBasketDao(): RoomBasketDao
}

1) entities

Room 라이브러리가 사용할 엔터티(테이블) 클래스 목록입니다.

2) version

데이터베이스 버전입니다

3) exportSchema

true로 설정하면 스키마 정보를 파일로 출력합니다.

6. helper 변수 생성

companion object {
        var helper: RoomHelper? = null
    }

helper = Room.databaseBuilder(this, RoomHelper::class.java, "room_basket6")
    .allowMainThreadQueries()
    .build()

위 코드를 통해 생성합니다.

helper 변수는 동반자 객체(companion object)로 설정해서 다른 액티비티에서 사용할 수 있도록 설정합니다.

이때 세 번째 파라미터 "room_basket" 부분이 실제 생성되는 DB 파일 이름입니다.

Room은 기본적으로 서브 스레드에서 동작하도록 설계되었기 때문에 allowMainThreadQueries() 옵션을 적용하지 않으면 앱이 동작을 멈춥니다.

그러나 실제 프로젝트에선 이 옵션을 그대로 사용하는 것을 권장하지 않으며, 단지 이 옵션을 사용하지 않기 위해선 코드가 복잡해지므로 일단 전 위처럼 사용했습니다.

이렇게 helper 변수를 생성하면 이제 Room을 사용할 수 있습니다.

7. 실제 사용

helper?.roomBasketDao()?.delete(mBasket!!)
val newList = helper?.roomBasketDao()?.getAll()?: listOf()

위처럼 helper 변수의 roomBasketDao() 의 메서드를 사용하면 됩니다.

8. 주의사항1 - 테이블 관련 정보 변경 시

테이블의 칼럼을 변경하거나 할 때는 그냥 사용할 수 없고, 새로운 이름의 테이블을 만들어야 합니다. 예를 들어서 제가 위에서 만든 테이블은 'room_basket'인데, 만일 테이블 관련 정보를 수정하였다면 'room_basket2' 이런 식으로 수정한 다음 사용해야 합니다. 저도 위 예시에서 'room_basket6'이 될 때까지 여섯 번의 수정을 거쳤습니다.

9. 마무리

오늘은 Room에 대해서 알아보았습니다. 구글이 강력하게 권장하는 만큼, 이번 시간을 통해 잘 정리해서 유용하게 사용하셨으면 좋겠습니다.

728x90
반응형