CS/Android, Kotlin

[Android] MVVM

dongdong216 2023. 4. 13. 22:36

면접준비용 MVVM - Android 정리 (맨 아래의 레퍼런스들을 꼭 확인해주세요.)

 

MVC

  • 구성 : Model, View(유저가 보고있는 화면), Controller
  • 흐름 : Controller에서 이벤트 발생 → 이벤트에 따라 Model 업데이트를 요청 → View에 전달 → View는 Model의 업데이트를 받아서 갱신
  • View, Controller에 로직이 총합되어 있어 테스트 코드 작성이 쉽지 않음. 또한 이렇게 구현한 코드에 특정 기능을 추가하려고 해도 어려움이 있음.

 

MVP

  • 구성 : Model, View, Presenter(View에서 요청한 정보를 Model로부터 가공하여 뷰로 전달)
  • 흐름 : 사용자의 액션을 View로부터 받음 → View는 받은 이벤트를 Presenter로 넘김 → Presenter에서 Model로 데이터를 요청 → Model은 repo를 통해 데이터를 받고 Presenter로 넘김 → Presenter에서 결과를 View로 통보 → View 업데이트
  • Presenter가 View, Model 사이를 잇는 가교 역할을 하므로 View와 Model 사이의 결합도가 강하던 MVC의 단점은 극복.
  • 그러나 Presenter와 View는 1:1 단계임. 따라서 View와 Presenter 사이의 의존성이 강함.

 

MVVM

  • 구성 : Model, View, ViewModel
  • View : Activity가 속함. DataBinding, ViewBinding 사용해도 Controller가 포함되어 View에 해당함.
  • ViewModel : 비지니스 로직을 처리함. 필요한 통지만 받아서 처리해주어야 함.
    • 여기서 생기는 고민 - 이 코드를 분리해야 하는가? 즉, 단순한 버튼 이벤트로 뷰의 간단한 부분만 바뀌는데 이걸 넘겨야 되나? 이런 고민들이 발생하게 됨.
  • 흐름 : view에서 이벤트 감지 → viewmodel에서 이벤트와 관련된 model의 메소드 호출 → model의 호출된 메소드가 작업 후 값 리턴 → viewmodel은 호출한 메소드로부터 받은 결과를 livedata에 저장 → view에서 livedata의 변경 감지해서 해당 값으로 뷰에 갱신

 

ViewModel?

ViewModel의 목표는 다음과 같음

  1. 코드의 분리
  2. 재사용 가능한 코드의 가능성
  3. 테스트를 통해 로직에 대한 오류 예측

즉 이상적인 뷰모델을 구현하려면 로직 분리 + 유닛 테스트 가능까지 고려해줘야 함. 뷰모델의 모든 함수가 테스트 가능하도록 구현이 되어야 함.

viewmodel에는 context를 넘기지 않는 것이 좋음. 가장 큰 이유는 생명주기가 다르다는 점이 있음. 위 사진과 같이 뷰모델의 생명주기는 뷰의 생명주기와 다름. 뷰의 생명주기가 끝났는데 viewmodel에 Activity/Fragment에서 할 수 있는걸 모두 접근할 수 있는 context를 넘기게 되면 충돌, 예외 문제가 발생하게 됨. 또한 뷰모델 자체는 테스트가 가능해야 하는데 안드로이드 코드가 들어가게 되면 테스트가 어려워진다는 점도 있음.

그렇다면 context가 필요한 상황에서 뷰모델을 사용하려면 어떻게 해야하는가? : AndroidViewModel 사용. AndroidViewModel은 Application context를 사용하고 있음.

// AndroidViewModel 상속
class VM(application: Application) : AndroidViewModel(application)

// context 필요한 곳에서 사용하는 방법
getApplication<Application>().applicationContext

 

내가 사용했던 MVVM

  • Data Binding, Live Data 사용, ViewModel 라이브러리 사용
  • 액티비티에서 이벤트 받고 비지니스적 처리가 필요하고 이 이벤트로 인해 뷰가 새로 갱신되어야 하는 경우 data binding - live data 사용. 그 외에 비지니스적 처리만 필요하면 viewmodel에서 처리만 해주고 끝났음. 그리고 해당 이벤트가 viewmodel에서 서버로 이벤트 갱신이 필요한 경우 repository pattern으로 만들어두었던 해당 repository를 사용한 메소드 호출

 

레퍼런스