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

제 앱에서 Room을 활용할때 어떤 방식이 더 효율적일까요?

0 추천

사진은 지난번에 썼던걸 재사용합니다. 그냥 대충 이런 기능이라는것 이다라는걸 설명하기위함입니다.

저렇게 Detail 아이템을 추가하고 저장버튼(사진에는 나타나있지않음)을 눌러서 전체 저장을 하고

첫화면으로 이동하게 되는 것인데요,

 

여기서 저 추가버튼과 저장버튼을 할때 어떻게 해야할지 잘 모르겠습니다. 

Room을 사용하려고 하고 있는데요,

지금은 Room이 없는 상태이기때문에 Detail 아이템을 추가하면 viewmodel 이 관찰해서

detail이 추가된 새로운 list를 postValue해서 화면을 업데이트하는 방식입니다. 즉 Room에 저장은 하지 않고있죠.

여기서 제가 생각하기에 화면 업데이트와 저장에 두가지 정도 방법이있는거 같은데 도와주세요.

 

1. 추가버튼을 눌렀을때 현재와 마찬가지로 DB에 저장하지 않고 LiveData 의 List에 postValue만 하여 화면만

업데이트하고 최종적으로 저장버튼을 눌렀을때 모든 Detail List를 저장하는 방법

 

2. 추가버튼을 눌렀을때 Detail 아이템을 하나하나 insert 하여 DB에 저장하고 화면 업데이트는

DAO에서 모든 리스트를 가져오는 Query문을 작성해 getAll() 하여 LiveData 형태로 리스트를 가져와 

화면을 업데이트하고 저장버튼을 눌렀을때는 1번과 마찬가지로 다시 Detail 리스트를 저장하는 방법.

@Dao
interface DetailDao {
    
    @Query( // 모든 리스트를 가져오는 query 문)
    fun getAllDetails() : LiveData<List<Detail>>
    
    @Insert
    fun insert(detail: Detail)

    @Insert
    fun save(list: List<Detail>)

    @Delete
    fun delete(detail: Detail)
}

 

 

이렇게 두가지 정도 생각햇는데요.. 어떤게 더 낫나요.? 다른 샘플 코드들을 보면,

저처럼 버튼을 눌러 추가할때는 2번 방법이 대부분이더라구요.

버튼을 눌러서 insert하고 화면 업데이트는 getAll을 LiveData<List<>>형태로 가져와서 observe해서

업데이트하더라구요..

근데 저는 저장까지 해야하잖아요? 그래서 추가버튼으로 인해 각각의 Detail이 insert 되어있는 상황에서 

또다시 저장버튼을 눌러 List<Detail>을 저장한다면

테이블의 형태가 꼬인다고 해야할까요? 그렇게 되어버려서 1번방법이 더 어울리지 않나 싶은데

어떻게하는게 효율적일까요?

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

1개의 답변

0 추천
기본적인 원칙은 single source of truth의 측면에서 먼저 생각해 보시는게 좋을 것 같습니다. 즉, 데이터의 원본은 한곳에서만 가지고 있는 여기서 데이터를 가져오거나 저장하는 형태로 코드가 구성되는 겁니다. 즉 DB가 source of truth가 되는게 맞는 것 같고, 데이터를 읽고 저장하는 부부은 DB를 통해 이루어지록 하는 것이 바람직하다고 봅니다. 그래야 데이터의 일관성이 보장되게 됩니다.

그리고 사용자가 입력한 내용이 바로 저장되어야 하는 게 요구사항이라면 첫번째 방법이 맞을 것 같고,
한꺼번에 저장해도 된다면 두번째 방법이 맞을 것 같네요.

한가지 고민이 될 수 있는 부분은 첫번째 방법같은 경우,  화면에 있는 뷰가 EditText이므로 사용자가 입력하는 내용이랑, db의 레코드랑 언제 싱크를 맞춰줄거냐 하는 점입니다. TextWatcher에서 할건지, 엔터키를 칠 때 할 건지, 포거스의 변경이 일어날 때 할건지... 어떤 형태로든 사용자가 입력한 데이터가 ViewModel 을 통해 DB에 저장되어야 하기 때문에, 이 부분을 잘 설계하셔야 할 것 같아요.

두번째 방법을 사용한다면, 일단은 현재와 같이 메모리에 사용자 입력을 받아서 저장한 다음 저장버튼을 누를 때 이 메모리에 있는 내용을 DB로 트랙잭션을 통해 처리하도록 해야하겠죠? 마찬가지로 첫번째 방법과 비슷한 고민이 생길 수 있습니다. 사용자가 EditText에 입력하고 있는 내용과 LiveData는 사용자 입력을 처리하지 않으면, 데이터가 동일하지 않게 되기 때문이죠.

UI의 구성상, 각각의 아이템에 대한 저장 버튼이 별도로 없기 때문에 각각의 아이템의 저장시점과 데이터를 DB로부터 가져와서 보여주어야 하는데, 현재 LiveData는 그렇게 되어있지 않기 때문에 이 부분을 어떻게 DB 중심으로 고칠지가 제일 관건이 될 것 같네요.
spark (225,780 포인트) 님이 2022년 3월 28일 답변
spark님이 2022년 3월 28일 수정
감사합니다. 선생님이 말씀하신걸 완벽하게는 이해는 못했지만..
다시 생각해봐도 저 기능에서 Detail을 추가란다고 바로 DB에 저장해야할 필요성은 없어보인다고 판단했습니다. 적어도 제 생각로는요.웹사이트의 글쓰기기능이나 타 앱들의  글 작성 도중에 혹시모를 팅김현상에 임시저장(?)의 기능을 생각한다면 추가할때마다 DB에 저장하는게 맞는것 같지만 저는 딱히 임시저장같은걸 고려하지않았거든요.

그래서 결론은 추가할때는 List에만 저장하고 observe하여 뷰를 업데이트 하고,
작성이 완료되고 저장버튼을 누른 시점에 모든 아이템을 DB에 한번에 insert하는 식으로 하기로 했습니다. 이렇게 해도되는지는 모르겠습니다.. DB가 아닌 List에 있는 데이터 가지고 읽고 뷰를 업데이트 하는것이요.

게다가 추가할때마다  DB에 저장하고 저장을 눌러 최종적으로 모든 리스트를 DB에 insert하는 코드도 작성해보았는데 추가할때 Db에 insert하고 또 저장버튼을 누를때 다시 list를 insert하다보니
테이블에 한번더 아이템이 insert되는 형태가 되더라구요..이건 제가 어떻게 뭐 처리를 안해서 그런걸수도 있습니다..또 추가할때 db에 넣고 저장 버튼을 눌렀을때 또 insert 하는거니 두번 반복해야하나 싶기도하구요..
예를 들어, 사용자가 입력을 하는 도중 디바이스를 회전한다면 입력하고 있던 데이터를 복구하지 않아도 된다면 말씀하신대로 처리해도 될 것 같네요. 저장을 해야한다면, 좀 복잡해 지구요.
아.. 화면의 회전을 생각을 못했네요..아이고..

근데 일단은 그문제는 접어두고 하던대로 진행해봐야겠습니다

문제점 지적해주셔서 감사합니다
디바이스 회전을 지원해야 한다면, 바로 문제해결을 하시는 걸 권장드려요. 상황에 따라서는 전체 UI와 아키텍쳐를 흔들어야할 가능성이 생기거든요.  configuration change를 지원하게 되면 시작점인 MainActivity부터 테스트 해보셔하구요, 특히 네비게이션이 잘 동작하는지 확인하셔야 해요. Navigation Component 를 사용한다면, 해당 라이브러리가 configuration change를 알아서 처리해 주기 때문에, 네비게이션 초기화가 한번만 되도록 해야 하고, FragmentManager같은 걸 사용해서 수동으로 처리했다면 Navigation 관련 뷰를 수동으로 뷰상태를 복구해주어야 합니다.

그리고 위의 입력과 같은 경우 EditText TextWatcher를 이용하지 않으면, 아마도 configuration change에 대해 사용자 입력을 완전히 안전하게 처리할 수 없을 겁니다. 이렇게 되면 TextWatcher의 onChange의 경우 사용자입력인지 코드에 의한 입력인지 구분해 주지 않기 때문에, 아마도 TextWatcher이 이벤트가 쓸데없이 여러번 먹거나 stackoverflow같은 에러에 빠진 확률이 있기 때문에, 이런 부분을 디테일하게 처리해주셔야 할 겁니다. Jetpack Compose같이 EditText 입력시 버퍼에만 들어갈 뿐 실제 화면 업데이터는 안이루어지면 좋은데, XML View는 이게 안돼서 님과 같은 use case에는 좀 골치가 아플 수 있습니다.

configuration change를 지원하지 않거나, 개별 입력에 대한 저장버튼이 존재한다면 처리가 쉬워질건데... 해당 사항을 지원해야 한다면, 어쨋든 지금 무시하고 지나가시면 안될 것 같아요.
...