안드로이드 앱 개발

Room Library 사용 방법 1 - Kotlin 본문

안드로이드앱

Room Library 사용 방법 1 - Kotlin

스텝바이스텝안드로이드 2021. 3. 31. 17:17

안드로이드 앱을 기획하고 만들다보면

반드시 마주하게 되는 선택의 순간이 있다.

 

바로 특정 데이터를 

데이터를 앱 내부에 저장하고 불러올 것인가 VS 서버에 저장하고 필요할 때마다 불러올 것인가

 

내부에 저장한다면

네트워크와 연결없이 자유자재로 사용할 수 있다는 장점이 있지만

데이터양이 너무 많이면 앱이 무거워진다는 점, 그리고

앱이 삭제되면 해당 데이터도 같이 삭제된다는 단점이 있다.

 

서버에 저장한다면

앱의 무거워지는 점은 고려하지 않아도 되고

(아무리 서버에서 정렬 및 필터로 가공된 데이터를 던져준다 하더라도 물리적인 용량이 크다면 어쩔 수 없는듯?)

앱이 삭제되더라도 데이터 접근 권한만 있다면 다시 불러올 수 있다.

 

그러나 문제는 서버구조를 기획하기 어렵고 (필자는 firebase rtdb사용함에도 불구하고)

데이터양이 많아지만 비용도 만만치 않기 때문에 고민이 된다.

 

======================서론 끝======================

 

사설이 길었지만 내부 SQLite를 좀더 쉽게 사용할 수 있게 해준

Room library의 사용법을 포스팅정리 해보자.

 

1. library를 implementation 해준다.

만약 sync now를 했는데, 오류가 난다면

 

build.gradle(:app) 상단에

plugins에 아래 속성이 추가되어 있는지 확인해준다.

    id 'kotlin-kapt'

다른 에러라면... 구글링!

 

2. Room의 요소

Database, DAO(Data Access Objects, Entities

 

developer.android.com/training/data-storage/room?hl=ko#kotlin

Developers에 잘 설명이 되어 있지만, 요약하자면

 

App이 직접 데이터베이스를 열람하는 것이 아니라

데이터베이스로부터 접근객체인 DAO를 요청해서 받아오고

DAO를 통해서 데이터베이스에 저장된 데이터들을 받아온다.

이때 받아온 데이터를 앱에서 사용하기 위해 Entity를 이용한다는 말인 것 같다.

 

3. 실제 예제 

Room Library를 활용해서 간단한 메모장을 만들어 보려고 한다.

 

Step1 Entity 클래스 만들기

@Entity(tableName = "memos") //Entity annotation을 달아주고 테이블 네임을 지정해준다.
data class MemoData2(
        @PrimaryKey val idx: Int, //memos라는 테이블에 primaryKey로 index를 사용
        @ColumnInfo(name = "date") val memoDate: String, // 컬럼명과 변수 이름, 타입 지정
        @ColumnInfo(name = "title") val memoTitle: String?,
        @ColumnInfo(name = "content") val memoContent: String

)

 

Step2 DAO 인터페이스 만들기

@Dao //Dao annotation
interface MemoDao { //interface

    @Query("SELECT * FROM memos") //모든 메모 불러오기
    fun getAllMemos(): List<MemoData2>

    @Query("SELECT * FROM memos WHERE idx == :idx ")
    fun findByIdx(idx: Int): MemoData2 //특정 메모만 불러오기 by idx

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(memoEntity : MemoData2) //메모 추가하기

    @Query("UPDATE memos set date = :date, title = :title, content = :content WHERE idx = :idx")
    fun update(idx: Int, date : String, title : String?, content : String) //메모 수정하기

    @Query("DELETE FROM memos WHERE idx = :idx")
    fun delete(idx: Int) //메모삭제하기
}

 

Step3 Database abstract 클래스 만들기

 

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

    abstract fun getMemeDao() : MemoDao

    companion object{

        private var INSTANCE: MemoDatabase? = null

        fun getInstance(context : Context) : MemoDatabase? {
            if(INSTANCE == null){
                synchronized(MemoDatabase::class){
                    INSTANCE = Room.databaseBuilder(
                        context.applicationContext,
                        MemoDatabase::class.java,
                        "memos.db")
                        .build()
                }
            }
            return INSTANCE
        }
    }
}

 

Step4 사용하기

간단하게 설명해서 Room을 간단하게 사용할 수 있을 줄 알았더니

제약사항이 많았다... (오류도 많고...)

 

1. 버전 에러... kotlin 버전과 library 버전이 같지 않으면 에러가 난다.

error 코드를 보고 버전 수정해야함

 

2. 기본적으로 내장 db는 메인 thread에서 돌릴 수 없다고 한다.

따라서 db를 사용할 때, AsyncTask나 Kotlin coroutines를 사용해서 background에서 돌려줘야 한다고 한다.

 

/*예를 들면 사용하고자 하는 액티비티에서
아래처럼 db를 불러오면 메인스레드에서 사용한다고 error가 난다.
*/
val db = Room.databaseBuilder(applicationContext,
        MemoDatabase::class.java, "memos").build() 
        
        
        

/* 따라서, 테스트할 때는 allowMainThreadQueries()를 붙여줘야한다.
*/
val db = Room.databaseBuilder(applicationContext,
        MemoDatabase::class.java, "memos").allowMainThreadQueries().build()
        
        
        
+ 추가적으로
//Database를 수정했다면 버전을 바꾸고 Migration도 해줘야하는데
// 나중에 추가적으로 포스팅하겠다.

//Migration 무시
val db = Room.databaseBuilder(applicationContext,
        MemoDatabase::class.java, "memos").allowMainThreadQueries().fallbackToDestructiveMigration().build()

 

참고 영상

www.youtube.com/watch?v=2mqt0j-a5xI&list=PLxTmPHxRH3VXHOBnaGQcbSGslbAjr8obc&index=8