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

ViewModel에서 Dispatchers.IO로 처리하는 대상을 activity에서 접근하기

0 추천

물론 Flow나 LiveData를 사용하면 다 해결됩니다만 공부를 위해서 MutableList를 사용해보고 있습니다.

'Cannot access database on the main thread since it may potentially lock the UI for a long period of time.' 이런 오류 메시지 때문에 viewModelScope를 사용했고 Dispatchers.IO로 RoomDB에서 items를 가지고 오는데 성공했습니다.

class CheckListViewModel(
   val app: Application
): AndroidViewModel(app) {
   var items: MutableList<Item> = mutableListOf()

   // fun getAllCategory(category: String) {
   //     items = RoomDB.getInstance(app)?.itemDao()!!.getAllCategory(category)
   //    Log.i(TAG, "items: ${items.toString()}")
   // }

    fun getAllCategory(category: String) = viewModelScope.launch(Dispatchers.IO) {
        items = RoomDB.getInstance(app)?.itemDao()!!.getAllCategory(category)
        Log.i(TAG, "items: ${items.toString()}")
   }

 

activity에서 items에 접근하는 게 문제인데요. 이게 어떨 때는 items를 받아 오고 어떨 때는 null을 반환합니다. 뭐 어떤 규칙이 있는 것도 아니고 오류 메시지를 보이는 것도 아니니 미치고 환장할 노릇입니다. 제 짧은 소견으로는 ViewModel에서 items를 받아오는 IO thread가 끝나는 여부에 따라 activity에 items를 정상적으로 보여주거나 그렇지 못하는 경우가 있는 게 아닌가 싶습니다. 제 생각이 맞는지요?

만일 그렇다면 ViewModel에서 items를 다 받아온 다음, 안전하게 activity에서 items에 접근하여 adapter로 뿌려줄 수 있는 방법이 있을까요?

 
최강로떼 (320 포인트) 님이 2023년 9월 27일 질문

1개의 답변

+1 추천

공부목적이라면  MutableLiveData의 소스코드를 확인해 보시면 좋을 것 같구요. 콜백패턴을 사용하시면 원하시는 처리가 간단하게 됩니다. 아래 소스를 참고하세요.

class CheckListViewModel(
   val app: Application
): AndroidViewModel(app) {
   var items: MutableList<Item> = mutableListOf()
 
    fun getAllCategory(category: String, onItemFetched: (List<Item>?) -> Unit) {
        viewModelScope.launch(Dispatchers.IO) {
           items = RoomDB.getInstance(app)?.itemDao()!!.getAllCategory(category)
           withContext(Dispatcher.Main.immediate) {
                  Log.i(TAG, "items: ${items.toString()}")
                  onItemFetched(items)
           }
        }
   }

}


// View
val checkListViewModel : CheckListViewModel by viewModels()

checkListViewModel.getAllCategory("categroy") { items: List<Items>? ->
      // TODO : Do something with items
}

그리고 LiveData와  비슷하게 처리를 하고 싶다면 observer패턴을 사용하시면 되구요. 코틀린에서는 Sequence란게 기본적으로 observe가 가능한 리스트입니다. yield 함수를 확인해 보세요.
https://kotlinlang.org/docs/sequences.html

spark (227,530 포인트) 님이 2023년 9월 27일 답변
spark님! 말씀해주신대로 동작합니다! 그러니까  { items: List<Items>? ->  // TODO : Do something with items } 이 코드 블럭이 getAllCategory()의 매개변수 onItemFetched로 넘어가는 거군요! 와... 제가 kotlin을 너무 모르고 있었네요. 알려주셔서 정말 고맙습니다!
...