안드로이드 방 안에 데이터 저장하기 (Room)

정진호·2022년 1월 5일
2
post-thumbnail

🤔 Room은 뭘까? What is Room???!?

  • "Room은 SQLite에 대한 추상화 레이어를 제공하여 원활한 데이터베이스 액세스를 지원하는 동시에 SQLite를 완벽히 활용합니다." https://developer.android.com/training/data-storage/room

  • Room은 ORM 라이브러리!? 그게 뭔디?
    ORM은 Object-Relational-Mapping으로 관계형 DB는 테이블을 사용하고 객체 지향 프로그래밍은 객체를 사용하기 때문에 불일치가 발생, 클래스와 테이블을 매핑하고 변환하여 일치시켜게 만드는 기술이 ORM 기술!

  • 그냥 쉽게 말해서, Room은 어플리케이션에서 데이터를 저장할 때 휴대폰 내장 데이터베이스를 이용하게 되는데, 이 때 쉽게쉽게 작성하게 도와주는 라이브러리!

🧐 응? 근데 android는 SQLlite 지원하잖아?

  • SQLite는 컴파일시 쿼리에 대한 에러를 확인하지 못하지만, Room은 쿼리 유효성 검사를 할수 있어!

  • SQLite는 schema 가 변경이 될때 SQL 쿼리를 수동으로 업데이트 해야하지만 Room은 쉽게 업데이트가 가능해!

  • SQLite는 ORM을 지원하지 않아서, 데이터를 객체로 변환하는 작업을 거쳐야해.

  • Room은 LiveData와 같은 옵저버 패턴의 데이터를 다룰 때 Observation 으로 생성하여 동작할 수 있지만 SQLite는 할 수 없어.

😅 오케이 Room, 좋아 보여!, Room은 어떻게 이루어져 있을까?

😗 Room은 세가지로 구성되어 있어!

  • DAO(Data Access Objects)
    여기는 인터페이스 형태로 만들어서 데이터베이스에 수행할 메서드를 정의 해두는 곳이야!
  • Entity는 데이터베이스의 테이블을 클래스로 정의한 곳이야!
  • Room Database
    Entity, DAO를 통합적으로 묶어서 데이터베이스를 생성하거나 버전 관리를 하는 추상 클래스야.

😙 자 이제 어떻게 쓰는 지 한번보자구!

위에 세개를 보았을때 뭐 부터 만들어야 할까?

👆 처음에는 Entity를 먼저 정의해야해!

@Entity
data class Todo(
   val title: String,
   val description: String?,
   val isDone: Boolean,
   @PrimaryKey val id: Int? = null
)
  • Entity 작성시
    한 개 이상의 PrimaryKey를 가지고 있어야해!
    위의 예시같은 경우에는 변수명이 테이블 컬럼 명이 되지만, 직접 이름을 설정하고 싶을 때에는
    @ColmunInfo("name")의 어노테이션을 이용해 컬럼 명을 설정할 수 있어

✌ 두 번째는 Dao를 정의해야 돼! Database안에 Dao를 정의해야되니깐!

@Dao
interface TodoDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertTodo(todo: Todo)

    @Delete
    suspend fun deleteTodo(todo: Todo)

    @Query("SELECT * FROM todo WHERE id = :id")
    suspend fun getTodoById(id: Int): Todo?

    @Query("SELECT * FROM todo")
    fun getTodos(): Flow<List<Todo>>

}
  • Dao 작성시
    인터페이스 형식로 설정하기!
    어노테이션(@)를 이용해서 @Insert, @Update, @Delete 기능을 사용하고,
    다른 쿼리문을 이용하고 싶으면 @Query("쿼리문")을 통해 작성 하면 돼!!


💪 마지막으로 Room Database 정의하기!

@Database(
    entities = [Todo::class],
    version = 1
)
abstract class TodoDatabase: RoomDatabase() {

    abstract val dao: TodoDao

}
  • Database 작성시
    추상클래스로 생성하고, 데이터베이스 어노테이션을 이용하기
    위의 version은 나중에 앱을 업데이트 하면서 테이블의 구조가 달라졌을 때
    이전 테이블과 구분을 짓기 위함이라고 생각하면 될듯!
    여기서 Dao를 접근하기 때문에 Dao를 반환하는 추상 메소드를 사용하거나 변수를 이용!
@Database(entities = arrayOf(RoomCalendar::class), version = 1, exportSchema = false)
abstract class RoomHelper: RoomDatabase() {
    abstract fun roomCalendarDao(): RoomCalendarInterface

    companion object{
        private var instance: RoomHelper?= null

        @Synchronized
        fun getInstance(context: Context): RoomHelper? {
            if (instance == null) {
                synchronized(RoomHelper::class) {
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        RoomHelper::class.java,
                        "room-helper"
                    ).build()
                }
            }
            return instance
        }
    }
}

위 코드는 RoomDatabase를 선언할때 싱글턴으로 DB를 초기화하는 코드!

//in mainActivity
 helper = RoomHelper.getInstance(mainActivity)!!
 helper.roomCalendarDao().getAll()

Activity에서 그냥 한줄 코드로 DB를 쉽게 생성하고 접근할 수 있어!
위 방법이 없었으면 그냥 쓸때마다 Builder 만들어가지고 context 넣고~ 😂

이제는 그냥 의존성 주입(di)를 이용하여 한줄 코드도 적을 필요가 없어졌음!
다음 편에서 DI(Dependency Inject)에 대해서 다루어 보도록 해볼게!

Reference

https://developer.android.com/training/data-storage/room
https://velog.io/@gang_shik/Android-Room
https://velog.io/@dev_jin/AndroidKotlin-Room
https://velog.io/@hyunho058/Room
https://velog.io/@l2hyunwoo/Android-JetPack-Room

profile
컴붕이

0개의 댓글