[Android] 데이터를 부탁해 Room!

moKo·2022년 4월 23일
0

Android

목록 보기
10/13
post-thumbnail

Room

Room은 안드로이드 Jetpack이 제공하는 데이터베이스 아키텍처이다.

쉽게 말해서 스마트폰 내장 DB에 데이터를 저장하기 위해서 사용하는 라이브러리이다.

기존에는 SQLite라는 DB엔진을 이용해 데이터를 저장해왔으나 각종 단점들 때문에 사용하기 어려웠는데, 이 문제들을 자동으로 처리하게 도와주려 나온 녀석이 바로 Room이다.

RoomSQLite를 완벽히 활용하며, 강력한 데이터베이스 엑세스를 지원하는 추상화계층을 SQLite에 제공한다.

Room의 구조 및 구성요소

위 사진에서 볼 수 있듯, Room은 3가지 구성요소가 존재한다.

  • Entity
    DB 내의 Table, 즉 DB에 저장할 데이터 형식으로 클래스의 변수들이 컬럼이 되어 Table이 된다.
    테이블명, 칼럼명, 칼럼타입, 키본키, 외래키 등등을 정의할 수 있게 하는 다양한 어노테이션을 제공한다.
    간단히 생각하면 하나의 정보단위로 사람의 이름, 나이, 번호라는 속성이 모여서 하나의 정보단위를 이루면 이것이 Entity이다.

  • DAO
    데이터베이스에 접근하여 수행할 작업을 메소드 형태로 정의한다. 데이터 삽입, 삭제, 업데이트, 쿼리 등등을 사용할 수 있게 하는 다양한 어노테이션을 제공한다.

  • Room Database
    데이터베이스의 전체적인 소유자 역할로 DB 생성 및 버전관리를 한다.
    Recyclerview어댑터와 같은 느낌으로 Entity만큼 정의된 Dao 객체들을 반환할 수 있는 함수들을 가지고 추상 클래스 형태로 정의한다.

Room DB에서 Dao를 가져오고 Dao를 사용하여 Entity에 접근한 뒤, Dao의 메서드를 사용하여 Entity의 항목들을 CRUD 한다 정도로 이해할 수 있다.

Android Setting

이제 직접 사용해보자.

일단 언제나 새롭게 뭘 시작할땐 Gradle설정부터 해줘야한다.

Gradle

plugins {
	id `kotlin-kapt'
}

...

val roomVersion = "2.4.2"

implementation 'androidx.room:room-runtime:$roomVersion'
kapt 'androidx.room:room-compiler:$roomVersion'

최신버전은 여기에서 확인할 수 있다.

Entity

@Entity
data class Person (
    var name: String,
    var age: String,
    var address: String
){
    @PrimaryKey(autoGenerate = true) var id: Int = 0
}

data class를 하나 생성해준뒤 @Entity 어노테이션을 붙여주고 변수 이름과 타입을 지정한다.

primary key는 키 값이기에 유일한 값이어야 한다. 직접 지정해도 되지만 authGenerate를 true로 주면 자동으로 값을 생성한다.

@Embedded라는 어노테이션을 사용하기도 하는데 이건 다른 데이터 클래스를 가져와서 하나에서 쓰기 위함이다.

street이라는 이름을 가진 다른 data class를 지금의 person이라는 data class에서 사용하고자 할때 @Embedded val street: street 이런식으로 사용해주면 사용이 가능하다

Dao

@Dao
interface PersonDao {
    @Insert
    fun insert(person: Person)
 
    @Update
    fun update(person: Person)
 
    @Delete
    fun delete(person: Person)
    
    @Query("SELECT * FROM Person") // 테이블의 모든 값을 가져와라
    fun getAll(): List<Person>
 
    @Query("DELETE FROM Person WHERE name = :name") // 'name'에 해당하는 유저를 삭제해라
    fun deletePersonByName(name: String)
    
    @Insert(onConfilct = OnConfilctStrategy.REPLACE) // 중복 시 덮어쓰기
    fun insertPerson(person: Person)
    
}

Interface를 하나 생성해준뒤 @Dao 어노테이션을 붙여주고 그 안에 메서드를 정의한다.

메서드마다 붙은 어노테이션은 이전에 Retrofit에서 다뤘던 CRUD의 그것과 동일하다.

@Query를 사용하면 어떤 동작을 할껀지 sql문으로 지정을 해줄 수 있다.

Room Database

@Database(entities = [Person::class], version = 1)
abstract class PersonDatabase: RoomDatabase() {
    abstract fun personDao(): PersonDao
    
    companion object {
        private var instance: PersonDatabase? = null
 
        @Synchronized
        fun getInstance(context: Context): PersonDatabase? {
            if (instance == null) {
                synchronized(PersonDatabase::class){
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        PersonDatabase::class.java,
                        "Person-database"
                    ).build()
                }
            }
            return instance
        }
    } 
}

데이터베이스를 생성하고 관리하는 데이터베이스 객체를 만들기 위해서 추상 클래스를 만들어야 한다. RoomDatabase클래스를 상속받고, @Database어노테이션으로 데이터베이스임을 표시한다.

@Database 우측 괄호안의 entities에는 아까 만든 entity를 넣어주면 된다.
만약 entity가 여러개라면 (entities = arrayOf(Person::class, Home::class) 처럼 콤마로 구분하여 arrayOf() 안에 넣어주면 된다.

안드로이드 공식문서를 보면 데이터베이스 객체를 인스턴스 할 때 싱글톤으로 구현하는 것을 권장한다. 객체 생성에 비용이 많이 들기 때문이다.

따라서 companion object로 객체를 선언해서 사용하면 된다.

Database 사용

var newPerson = Person("홍길동", "26", "서울시 강남구")

val db = PersonDatabase.getInstance(applicationContext)
        db!!.PersonDao().insert(newPerson)

이런 식으로 데이터를 정의해두고 insert를 하면 newPerson이 데이터베이스에 추가된다.

하지만 이런식으로 실행하면 "Cannot access database on the main thread since it may potentially lock the UI for a long period of time" 라는 오류가 발생하는데,
"오래 걸리는 작업이니까 바쁜 나 말고 다른 애 시켜" 정도로 해석하면 된다.

여기서 저번에 공부했던 Coroutine으로 비동기 처리를 하면 된다.

val db = PersonDatabase.getInstance(applicationContext)
        CoroutineScope(Dispatchers.IO).launch { // 다른애 한테 일 시키기
            db!!.PersonDao().insert(newPerson)
        }

내용 및 사진 출처, 이해를 도와준 분들 🙏 ( 클릭 시 이동됩니다 )

profile
🔥 Feelings fade, results remain

0개의 댓글