마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

Room 초기 데이터 설정.

0 추천

 

Room에 초기데이터를 설정해서 그 데이터로 앱에 목록을 뿌려주려고하는데..

이게 만들다 보니 제가 설정한 것과 조금 달라서 여쭈어봅니다.

현재 위 화면의 운동 목록 데이터들을 그냥 strings 파일에 <string-array> 형식으로 저장해놓고

viewmodel에서 가져다와 쓰고 있거든요..

근데 저는 현재 strings 파일에 이 운동 데이터들이 있는게 꼴보기싫어서(너무 길고 지저분)해서 

DB에 초기데이터로 저장후에 불러와서 사용할 예정이었는데

DB 초기데이터 설정관련 샘플 코드들을 보는데..

죄다 결국은 클래스 파일 내에서 데이터를 생성해서 insert하더라구요..

예시1

@Module
class DatabaseModule {
    @Provides
    fun provideDatabase(context: Context):AppDatabase{
        return Room.databaseBuilder(context, AppDatabase::class.java, "event.db")
                .addCallback(object: RoomDatabase.Callback(){
                    override fun onCreate(db: SupportSQLiteDatabase) {
                        super.onCreate(db)
                        db.execSQL("insert into category (name, color) values ('수면', '#123456');")
                        db.execSQL("insert into category (name, color) values ('공부', '#456789');")
                        db.execSQL("insert into category (name, color) values ('운동', '#A98765');")
                    }
                    
                })
                .build()
    }
}

예시2

fun fillInDb(context: Context){
            CoroutineScope(Dispatchers.IO).launch {
                getDatabase(context)!!.userDao().addUserDb(
                    USER_DATA
                )
            }
        }

private val USER_DATA = arrayListOf(
    User(0,"Han",20),
    User(0,"Lee",25)
)

예시3

private fun buildDatabase(context: Context) =
                Room.databaseBuilder(context.applicationContext,
                        DataDatabase::class.java, "Sample.db")
                        // prepopulate the database after onCreate was called
                        .addCallback(object : Callback() {
                            override fun onCreate(db: SupportSQLiteDatabase) {
                                super.onCreate(db)
                                // insert the data on the IO Thread
                                ioThread {
                                    getInstance(context).dataDao().insertData(PREPOPULATE_DATA)
                                }
                            }
                        })
                        .build()

        val PREPOPULATE_DATA = listOf(Data("1", "val"), Data("2", "val 2"))

 

이런식으로 list 데이터를 클래스 파일에서 만들어서 insert하던데 초기데이터를 설정하는 예시코드라 그런지는 모르겠지만 다 이렇게 하더라구요..

물론 개발자 문서에는 asset인가? 그거랑 파일에서 가져오는 방법 있던데 메모리 내 Room 데이터베이스는 지원안하다는데 

이게 무슨 말인지 정확하게 몰라서 Callback 방법을 사용한 코드를 설정해놓은 상태입니다.

결국 이 Callback 방법은 내가 직접 데이터들을 만들던지 string.xml 파일에서 가져오던지해서 DB에 

insert해야할듯한데..

저는 목적이 strings.xml에 있는 데이터들을 거기 안두고 DB에 두고 가져오는게 목적이라..

어떻게 방법 없을까요?

아니면 초기설정이기에 그냥 insert하고 strings에 데이터는 지워주면 되는건가요?

codeslave (3,940 포인트) 님이 2022년 5월 14일 질문

1개의 답변

0 추천
목적에 부합하는 여러가지 옵션 중에서 장단점을 비교해서 제일 적합하다고 판단이 되는 걸 선택하시면 될 것 같은데요. 가능한 방법으로는

1. 찾아보신 예제처럼 초기화 코드를 실행하는 방법. 하드코드된 데이터 사용

2. 1번처럼 하되 현재 처럼 초기 데이터를 리소스에서 가져오는 방법

3. 1번처럼 하되 초기 데이터를 리소스를 assets에 json 등의 포맷으로 가져오는 방법

4. 1번처럼 하되 초기 데이터를 파이어베이스나 서버 등 리모트에서 데이터를 가져오는 방법

5. 초기데이터가 미리 들어가 있는 Room DB를 같이 배포하는 방법

선택의 기준은 구현과 테스트가 쉽고, 추후에 변경사항 생길 때 적용이 쉬운 방법 정도로 하시면 되지 않을까요.
spark (226,420 포인트) 님이 2022년 5월 14일 답변
현재 제가 원하는것이 strings 파일을 사용하지 않고, 코드내에서도 직접 데이터를 생성해서 넣는 방법을 사용하지 않는 것을 원하는데..(깔끔?한 코드를원해서..)

하드코드가 예제처럼 리스트같은 데이터를 직접 넣는것 말하는것이죠?
그렇다면 1번방식은 부합하지않는것같구요..
2번은 여전히 현재도 사용하고 있는 strings.xml에서 가져오는것같아 아닌것같구요..

3번은 개발자문서에서도 있는 방법인데 in-memory Room DB에서는 지원을 안한다는데 이게 뭔소린지 모르겠어서 사용을 안하고 있고 또한 유튜브에서도 영상을 봤는데 업데이트할때 DB파일을 수정하고 기존 DB파일을 삭제하고 새로운 DB파일을 붙여넣기하고 등등 좀 번거로워보이더라구요..

그럼 4번밖에 선택지가 없는건가 싶네요..그런데 4번을 사용하면 또 Room을 사용 안해도 된다는 뜻이죠?

5번은 무슨말인지 잘모르겠구요 ㅋㅋ

암튼 선택을 잘해야겠네요
5번은 RoomDB를 앱에서 생성하지 않고 필요한 데이터가 들어있는 상태로 assets폴더에 배포해서 그대로 사용할 수 있어요. 앱에서는 DB를 생성하는 대신 assets폴더에 있는 DB로 링크를 시켜주면 됩니다.
감사합니다 1번처럼 하라는뜻이 db.execSQL을 사용하라는 말씀이신가요? 아니면 addCallback을 사용하라는 말씀이신가요?

그리고 4번의 경우 파이어베이스나 서버등 리모트에서 데이터를 가져온다는 말은 리모트에 데이터가 저장되어있다는 말인데..1번처럼 안해도 되지않나요?
바로 리모트에서 가져온 데이터를 뷰에 뿌려주면 되는것아닌가요? 왜 1번처럼 하고 데이터를 파이어베이스같은곳에서 가져오라는말씀인지 잘모르겠습니ㅏ
1-4 번의 차이는 런타임에 DB에 저장할 초기데이터를 어디에 위치시키느냐 하는 겁니다.
그리고 4번의 경우는 파이어베이스나 서버는 네트워크를 통하기 때문에 인터넷이 필요하지만 일단 DB에 저장하고 나면 네트워크가 필요없고 실행속도도 네트워크보다는 빠르겠죠. 이런 이유로 로컬에 DB를 두어서 캐시용도로 사용하기도 합니다. 잘 구조가 갖춰진 앱들이 사용하는 방식 중의 하나가 요청이 오는 경우 DB에 요청데이터가 존재하는 경우 먼저 이걸 리턴하고, 그 사이 서버에 접속해서 최신데이터를 가져온 후 DB에 저장하고 이 데이터를 다시 리턴합니다. 서버에서 에러가 나더라도 DB에만 데이터가 있으면 사용자에게는 데이터를 보여줄 수 있죠. 이러게 하면 앱이 항상 데이터를 처리할 수 있는 responsive app(반응형앱)이 되는 겁니다. 이전에 질문하셨던 Flow가 이런 형태의 데이터 흐름을 구현하는데 적합합니다.
어음.. 선생님이 하는 말씀이
그럼 데이터를 저장하고 가져오는 방식이 리모트(서버,파이어베이스)나 로컬 방식이 있는데, 초기 데이터를 파이어베이스에다가 하고 파이어베이스에 설정한 데이터를 가져와서 이걸 뷰에다가 바로 뿌리는게 아니라..

로컬(Room DB)에다가 이 가져온 데이터들을 넣어서
다시 Room에서 이 데이터를 가져와서 최종적으로 뷰에다가 뿌린다.

이렇게 해석이 되는데 맞나요?

말만보면 파이어베이스나 서버에 있는 데이터를 가져와서 바로 뷰에다 뿌리지 않고 다시 DB에 저장하고 DB에서 이 데이터를 쓰는 방식이 굉장히 비효율적으로보이는데, 왜냐하면 한번만에 해도 될일을 두번하는거니까..?
이게 오히려 효율적인가요?
오프라인을 지원하기 위해서예요. 인터넷이 끊긴 상태에서도 로컬 DB에 있는 데이터를 보여줄 수 있기 때문에 user experience 측면에서 상당히 이점이 생기는 거죠. 물론 꼭 실시간 데이터만 보여줘야 한다면 이 방법을 사용하면 안되겠지만, 대부분의 앱에는 해당하죠.
코드량은 좀 많아지지만 거기에 따른 이점도 분명히 존재하는 방식이고 구글과 같은 메이져 브랜드들은 기본적으로 이런 방식으로 동작을 합니다.
...