Room 무작정 사용해보기

“Android 로봇은 Google에서 제작하여 공유한 저작물을 복제하거나 수정한 것으로 Creative Commons 3.0 저작자 표시 라이선스의 약관에 따라 사용되었습니다.”


개요

안드로이드에서 DB를 사용하는 방법은 2가지가 있다.

  • DB가 연동되어 있는 외부 서버와 통신하기
  • 로컬 DB 사용하기 (SQLite)

보통 Oracle이나 MySql을 연동해서 사용하는게 일반적일텐데
안드로이드는 왜 사용하는 방법이 갈리냐면
안드로이드에서는 직접적으로 DB를 연동할 수 없다.

보안 상의 문제로 Oracle과 같은 DB에 바로 연동할 수는 없다고 하지만
대신 내부 DB로 SQLite를 활용하는 방법을 제공해왔다.

그리고 그 방법을 더 발전시킨 것이 바로 Room이다.

자세한 것은 공식 문서를 참고하면 되겠다.

구현

Room을 사용하려면 3가지 구성요소를 만들어야 한다.

  • Entity
    쉽게 말하면 Table이라고 생각하면 된다.
  • DAO
    흔히 말하는 CRUD 매트릭스를 정의하는 Interface이다.
    Room의 어노테이션을 통해 쉽게 구현할 수 있다.
  • RoomDatabase
    데이터베이스 홀더를 포함하여 데이터베이스와 연결하기 위한 여러가지 setup을 하는 추상클래스이다.

Entity

@Entity
data class RoomEntity(
    @PrimaryKey(autoGenerate = true) var id: Int,
    @ColumnInfo(name = "test_value") var testValue: String
)

어노테이션을 통해 Entity임을 알려주고
Table 설계하듯이 작성하면 된다.

  • @PrimaryKey
    PrimaryKey를 지정하는 어노테이션으로
    autoGenerate를 지정해주면 자동으로 키값이 1씩 증가한다.
  • @ColumnInfo
    실제 DB에 저장될 컬럼의 이름을 명시하는 어노테이션으로
    생략할 경우 변수의 이름으로 저장된다.

DAO

@Dao
interface RoomDAO {
    @Query("SELECT * FROM RoomEntity")
    fun selectRoom() : List<RoomEntity>

    @Insert
    fun insertRoom(entity: RoomEntity)

    @Update
    fun updateRoom(entity: RoomEntity)

    @Delete
    fun deleteRoom(entity: RoomEntity)

}

삽입, 삭제 등 CRUD 매트릭스를 정의하는 Interface이다.
Insert, Update, Delete는 어노테이션을 통해 구현되며
매개변수로 들어온 entity를 처리한다.

Database

@Database(entities = [RoomEntity::class], version = 1, exportSchema = true)
abstract class MyRoomDatabase : RoomDatabase() {
    abstract fun getRoomDAO() : RoomDAO

    companion object {
        private var instance: MyRoomDatabase? = null

        fun getInstance(context : Context) : MyRoomDatabase {
            instance?.let {
                return it
            } ?: run {
                instance = Room.databaseBuilder(
                    context.applicationContext,
                    MyRoomDatabase::class.java,
                    "testRoom.db"
                ).build()
                return instance!!
            }
        }
    }
}

Activity

이제 필요한 것은 다 만들었으니 사용해보자

        // UI init.
        binding.apply {
            btnRoom.setOnClickListener {
                Thread {
                    Snackbar.make(it, "저장되었습니다.", Snackbar.LENGTH_SHORT).show()

                    val dao = MyRoomDatabase.getInstance(this@RoomActivity).getRoomDAO()
                    dao.insertRoom(
                        RoomEntity(0, edtRoom.text.toString())
                    )

                    val entityList = dao.selectRoom()
                    runOnUiThread {
                        tvRoom.text = ""
                        entityList.forEach {
                            tvRoom.text = tvRoom.text.toString().plus("\r\n ${it.testValue}")
                        }
                    }
                }.start()
            }
        }

실행시켜보면 아래와 같이 잘 작동하는 것을 볼 수 있다.

참고로 Room을 실행할 때에는 비동기 처리를 해주어야 한다.
메인스레드에서 실행시켰다가는
아래왜 같은 시뻘건 Exception이 반겨준다.

java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
// DB 작업이 많을 경우 UI가 멈출 수 있기 때문에 메인스레드에서 실행하는 것은 지양해야한다.

으으

필자는 예제를 위해 Thread를 사용했지만
Coroutine이나 다른 방법을 사용해도 좋다.
참고로 AsyncTask는 안드로이드 11부터 Deprecated 되었으니 조심하자.

개인적으로 공부했던 것을 바탕으로 작성하다보니
잘못된 정보가 있을수도 있습니다.
인지하게 되면 추후 수정하겠습니다.
피드백은 언제나 환영합니다.
읽어주셔서 감사합니다.

좋은 웹페이지 즐겨찾기