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

안드로이드 코틀린 mvvm 질문

0 추천
안드로이드에서 만든 AAC가 아닌 일반적인 mvvm의 형태로 개발하면서 공부 중에 있습니다.

그런데 mvvm을 사용하면서도 이게 맞나 참 헷갈리네요.

view viewmodel model 로 이루어진게 mvvm이잖아요.

 

view는 말 그대로 보이는 영역, xml 같은 부분을 의미하고

viewmodel은 비지니스 로직

model 은 정확히 뭘 하는 녀석인지 아직도 감이 안잡힙니다.

 

제가 현재 만들고 있는 것은 retrofit2을 사용해서 서버와 통신해서 데이터를 받아오는데요. 해당 데이터를 받아와서 데이터를 가공해서 액티비티가 종료될 때 까지 받은 데이터를 가지고 있어야 한다면 ViewModel에서 retrofit2를 호출하고

호출 결과를 model에 변수나 data class로 보관해야 하나요?

 

그것도 아니면 model에서 retrofit2를 호출함과 동시에 받은 데이터를 보관해야 하나요?

 

-----------------------------------------------------------------------------------------------------------------------

그리고 또 궁금한게 있는데요. MutableLiveData의 경우 뷰에서 접근하지 못하도록 보통 private을 걸잖아요. 그 대신 LiveData를 이용해서 MutableLiveData를 가져오도록 보통 구현하는거 같더라고요. 말 그대로 뷰에서는 LiveData를 통한 읽기만 가능하고 수정은 viewmodel에서 가능한거죠. 하지만 또 값이 바뀔 때 마다 뷰에서 실시간으로 바뀔 수 있도록 해야하는 거고요. 그럼 이런 뷰에서 실시간으로 읽어야하는 MutableLiveData의 경우 viewmodel에 만드나요? 아니면 model에 만드나요?

 

model에 만들어서 사용하려하니 경고창? 에러는 아니고 거기에 해당 변수는 private을 권장하는 것 처럼 나오더라고요.

 

이런 고민을 하는 이유는 model에서 retrofit2를 이용해서 서버에서 데이터를 받아오면 그 데이터를 mutableLiveData에 넣고 그걸 View와 연결해서 보여줘야 하기 때문입니다. 그런데 가끔 비지니스 로직을 구성하는 viewModel에서 해당 mutableLiveData의 value를 수정해줘야 할 때가 있습니다. 그러다 보니 model에 넣고 private을 걸면 viewModel에서 접근이 안되고 viewModel에 MutableLiveData를 넣고 Model에서 retrofit2를 호출해서 데이터를 받아오면 그걸 viewModel에 있는 MutableLiveData에 넣는게 맞는지 잘 모르겠습니다.

 ----------------------------------------------------------------------------------------------------------------------

질문이 좀 많네요 ㄷㄷ

그리고 activity를 넘어갈 때 이런 동작은 뷰에서 한다고 하시더라고요. 그래서 activity class에서 구현을 하는데 LiveData를 이용해서 값이 바뀌면 뷰가 넘어가는 방식도 되지만 저는 그냥 인터페이스 하나 만들어서 해당 뷰에 인터페이스를 상속시키고 뷰 모델에도 연결하고 뷰 모델에서 인터페이스의 함수를 호출하면 뷰에서 다음 화면으로 넘어가거나 다이얼로그를 보이도록 했거든요. 이렇게 해도 상관없나요?

 

이렇게 했던 이유가 viewModel은 view에 대한 정보를 가지고 있으면 안된다고 하더라고요. 그러니 activity에 대한 정보도 없어야 하고 context에 대한 정보도 되도록 안가지고 있는게 좋다고 하길래 이렇게 구현을 했습니다.

----------------------------------------------------------------------------------------------------------------------
마지막으로 클릭 이벤트의 경우 ViewModel에 함수를 하나 만들고 xml에 onClick 을 이용해서 viewModel의 함수와 연결을 했거든요.

그렇다면 예를 들어 스크롤 체인지 이벤트 같은 경우(스크롤 움직일 때 나타나는 리스너 이벤트)도 viewModel에서 만들어서 xml에 연결해야 하나요? onClick은 xml에서 제공을 해서 연결하기 편했는데 다른 리스너 같은건 어떻게 연결해야 하나요?

설명이 좀 어렵네요... 어떻게 보면 첫 질문과 두번째는 이어지는 질문이긴 한데... 대부분 게시물들이 엄청 간단한 예제만 있거나 심지어는 잘못 되어있는 정보도 있는 것 같아 여기에 글을 올립니다.
키리링 (840 포인트) 님이 2022년 9월 2일 질문
키리링님이 2022년 9월 2일 수정

1개의 답변

0 추천

MVVM에 대한 개념이 약간 다른듯 해서 제가 아는 걸 요약해 볼게요.

ViewModel: 뷰의 상태를 보관하는 View state hodler로 Model로 부터 데이터를 가져와 View에 전단하는 중계역할.
Model: 어플리케이션에 필요한 데이터 처리를 담당, API, 비지니스로직에 여기에 속함.

데이터의 보관은 프로젝트의 상황에 따라

ViewModel에 할 수도 있고 모델 단에 메모리나 DB에 보관할 수도 있고, 필요하다면 Retrofit의 캐시를 사용할 수도 있습니다. 이건 순전히 프로젝트의 상황을 봐서 결정할 문제이구요, 특히 님이 유지보수하기에 적합한 방법이어야 합니다.

안드로이에 종속적이지 않는 MVVM을 사용할 계획이면 ViewModel클래스와 LiveData는 사용을 피하셔야 합니다. 이 클래스들은 안드로이드 SDK의 일부입니다. Kotlin을 사용하신 다면 LiveData대신 Flow가 좋은 대안인데, 문제는 안드로이드 ViewModel없이 많은 추가코드를 작성해야 할 수도 있습니다.

LiveData를 사용하시면 다면 뷰는 LiveData를 observe만 하면 되고, 데이터의 변경은 ViewModel에서 LiveData를 통해 하면 뷰쪽으로 데이터가 전달됩니다.

네비게이션은 View의 역할입니다. 다만 여기에 필요한 데이터는 ViewModel을 통해서 가져오는 경우가 많습니다. ViewModel에 갈 필요가 없다면 그냥 뷰에서 처리하셔도 되겠죠.
 
View에 인터페이스를 구현하고 ViewModel에 해당 인터페이스를 전달해서 ViewModel에서 인터페이스를 직접 호출하는 방식은, MVP라고 하는 패턴과 아주 유사합니다. 그렇게 해도 안되는 건 아닌지만, 이렇게 되면 뷰와 뷰모델의 통신방법이 두가지가 존재하게 되는 거라 코드 측면에서 추후에 헷갈리기 쉽고, LiveData를 굳이 사용할 필요가 없게 됩니다. 안드로이드 ViewModel를 사용할 필요없이 그냥 일반 클래스를 사용하는게 나을 수도 있구요. 왜 안드로이드 ViewModel과 LiveData가 도입되었는지 이해할 필요가 있습니다. (주된 이유는 라이프사이클 처리)
 
뷰모델이 뷰에 대한 정보를 갖고 있지 말라는 이유는, 님이 말하는 이유 외에 좀 더 안드로이적으로 말하면,ViewModel은 Activity, Fragment보다 라이프사이클이 깁니다. 따라서 뷰에 대한 참조를  ViewModel이 가지고 있으면, 어느 시점에서 View 에 대한 참조는 null이 될 수 있습니다.  주의를 하지 않으면 문제가 생길 소지가 있기 때문에, 문제의 원인은 애초에 없애는게 바람직합니다. 인터페이스를 쓴다고 해도, 인터페이스의 구현체는 어차피 뷰일 때니 결과적으로는 마찬가지입니다. 다만 테스트를 좀 더 쉽게할 수있도록 하는 이점은 있을 겁니다.
 
뷰에서만 필요한 이벤트 처리는 뷰에서만 하시면 되고 ViewModel로 넘길 필요가 없습니다. 하지만 스크롤 이벤트가 발생했을 때 ViewModel에 있는 데이터를 변경해야 한다면 ViewModel에서 처리를 해야 겠죠. 하지만 DataBinding을 사용하는 것이 아니라면, View.OnClick이벤트 등을 ViewModel에 직접 만드는 것 보다는 뷰 쪽에 해당 리스너를 만들고 그 안에서 ViewModel을 호출하는 것이 좋습니다. ViewModel에 가능하면 Android 관련 참조가 없어야 테스트 등이 용이합니다.

 

spark (226,420 포인트) 님이 2022년 9월 2일 답변
이거 제가 잘 못 알고 있었던게 맞는거 같네요. 여러 게시물들을 봤는데 어디는 viewmodel이 비지니스 로직을 구성한다고 하고 말씀하신데로 model에 한다는 사람도 있어서 헷갈렸네요. 덕분에 알아갑니다.

일단은 일반적인 mvvm을 구성했지만 확실히 공부를 해보니 liveData 같은 것도 사용해야 되고 해서 결국 AAC viewmodel을 활용해서 mvvm 을 구성해야 할 듯 합니다. 이미 엄청 많이 개발했는데 이걸 뒤엎기도 뭐하고 참... 대부분의 비지니스 로직이나 통신 로직을 viewmodel에 만들었거든요. 골치 아프네요...

제가 궁금한게 있어서 하나만 더 물어보겠습니다.
다름이 아니라 인터페이스를 활용해서 제가 화면을 옮겨 다닌다고 했잖아요. 그랬던 이유는 viewModel에 onClick에 들어갈 함수를 만들었는데 viewModel에는 엑티비티, content의 내용을 담으면 안된다고 해서 viewModel에 있는 onClick을 눌러도 이동을 할 수 없다는 것 이었습니다. 그렇다고 화면 전환을 위해 LiveData<boolean> 형태를 만들어서 onClick 안에 넣어서 누르면 상태 값이 바뀌게 하고 상태 값이 바뀌면 화면을 전환한다던지 하기에는 쓸데 없는 변수를 만드는 기분이더라고요.

그럼 차라리 엑티비티에 setOnClickListener 을 만드는게 맞을까요?
네비게이션을 유발시키는 데이터가 ViewModel에 위치한다면 ViewModeld의 LiveData를 통해 이벤트를 받아서 뷰에서 화면이동을 시키는게 일반적입니다. 보통 이건 LiveData를 사용할 경우 One-time 또는 One-off event 처리라고 합니다.그러나 단순히 버튼을 눌렀을 때 화면을 이동하는 거라면  ViewModel을 거칠 필요가 없어 보입니다.
안드로이드 개발자 문서에 아키텍쳐 관련한 문서들이 있습니다. 보시면 샘플코드들도 많이 나와 있습니다.
...