Android에서의 MVVM은 무엇이고 왜 사용하는가
이전 기록에서 아키텍처 개선을 위한 이야기를 했었다. 개선을 위한 컴포넌트(Component)들을 사용하고, MVVM 디자인 패턴을 적용하기로 했었다. 이번 기록에서는 이 MVVM 디자인 패턴이 무엇인지를 다뤄 볼 예정이다.
관심사 분리
초보 개발자들(본인)이 실수하는 많은 것들 중 하나는, Activity나 Fragment 클래스에 모든 코드를 작성하려 한다는 것이다. 때문에 앱의 동작 속도가 느려질 수 밖에 없고 유지보수가 어렵게 되는것은 덤이며 메모리 관리에도 많은 어려움이 발생한다. 따라서, 최대한 클래스의 의존성을 최소화 하는 것이 좋다. (추후에 의존성 주입에 대한 내용도 포스팅 할 예정이다.) 아직 초보인 본인이 봤을 때는 로직들을 분리하고 의존성을 최소화 하게 되면, 한 로직에서 문제가 발생했을 때도 앱이 강제종료 되는 상황을 줄일 수 있으며 이후에 버그를 잡는 데도 수월하다. 의존성이 최소화 되었기 때문에 "이게 없으면 절대 안 돼!" 라는 극단적인 상황은 웬만하면 피할 수 있다는 이야기인 것 같다.
아무튼, Android에서는 이러한 관심사 분리로 MVVM 패턴을 권장하는 것 같다. 따라서 관련 라이브러리도 제공하고 있으며 업계 트렌드도 따라가는 추세(라고 들었다.)이다.
MVVM의 개요
일단 Google에서도 설명하고 있는 내용인데, 아래 다이어그램을 보면 된다.
위에서 말한 종속성을 최소화 하기 위해 많은 노력(?)을 한 것을 볼 수 있다. 각 구성요소가 한 수준 아래의 구성요소에만 종속되어 있는 것을 볼 수 있다. 여태까지의 본인이 갖고 있는 지식을 총동원 해보자면...
Activity/Fragment는 View이다. 화면에 표시되는 레이아웃에 대해 관여하는 놈이다. xml과 같은 layout에 대해 관여한다.
ViewModel은 View에서 사용할 데이터나, 비즈니스 로직을 구성하게 된다. Activity나 Fragment에서 볼 수 있도록 데이터를 준비하고, 사용자 상호작용에 반응하는 클래스이다. ViewModel은 View에게 상태 변경을 전달한다. 이를 View에서 받아 UI를 변경하는 로직을 수행한다.
UI로직과 비즈니스 로직을 분리했을 때 좋은 상황을 예로 들자면, 화면이 회전 되었을때이다. 모든 로직들을 관심사 분리 없이 Activity나 Fragment클래스에 때려박게 되면 화면이 회전되었을 때 다시 그려지고 실행이 되기 때문에 미디어를 재생 중이라면 끊어지고 다시 재생되는 현상이 발생한다. 하지만 관심사를 분리해 놓는다면 비즈니스 로직은 UI로직에 관해 알 수 없으므로 화면이 회전하건 말건 영향을 받지 않는다.
다이어그램에 나와있는 View 즉, UI관련 로직은 View에서 관리하고, 데이터와 비즈니스 로직은 ViewModel에서 관리한다. 또 여기서 ViewModel은 Model과 함께 데이터를 가져오는 행위를 한다. 이러한 상황에서 알 수 있는 사실은, View는 Model을 모르지만 ViewModel을 알고 있고, ViewModel은 View는 모르지만 Model은 알고 있다.
위에서 말한 상태변경에 대해서는 LiveData라는 놈이 있는데 이것을 같이 활용하여 View에서 상태변경을 옵저빙 하여 UI관련 로직을 처리하게 된다. 이렇게 종속성을 최대한 줄여놓으면, 유지보수가 쉬워질 뿐더러 사용자에게 최상의 경험을 제공해 줄 수 있다고 한다.
종속성을 더 줄여주기 위해, DI(Dependency Injection)라고 하는 '의존성 주입' 이라는 개념이 또 존재하는데, 이것도 나중에 포스팅 할 예정이다. 차근차근 알아가는데 중심을 두자.
ViewModel in Android
Android에서는 ViewModel이라는 컴포넌트를 제공한다. ViewModel 에 대해 이야기를 하려면 위에서 말한 내용들을 다 알고 있어야 한다. 앞서 우리는 화면 상에서 변경이 일어날 때 발생할 수 있는 이슈들에 대하여 이야기를 했었다. 이는 생명주기와 깊은 연관이 있다.
왼쪽 부분을 보게 되면, 위에서 말한 화면 회전 시의 생명주기는 onPause-onStop-onDestroy 의 과정으로 액티비티가 종료되고 다시 onCreate-onStart-onResume 순으로 다시 그려지는 것을 볼 수 있다. 이런 생명주기를 가졌기 때문에 UI로직을 담당하고 있는 Activity나 Fragment 클래스에 데이터를 저장하거나 불러오는 로직을 넣게 된다면 문제가 발생하게 될 것이다. 반면 ViewModel은 한 번 생성되면 끝까지 유지되기 때문에 화면이 회전되어도 전혀 문제가 없다.
사실 Activity/Fragment의 상태를 저장할 수 있는 onSaveInstanceState라는게 있다. 하지만 이는 비교적 간단한 데이터만 담을 수 있고, 크기가 제한적이기 때문에 복잡한 구조의 데이터는 담을 수 없다. 이를 해결하기 위한 것이 바로 ViewModel 컴포넌트 이다.
굳이 Android 플랫폼이 아니더라도, MVVM패턴을 적용할 수 있으나, Android에서 굳이 ViewModel 컴포넌트를 제공하는 이유는 앞서 말한 과정들을 ViewModel에서 해주기 때문이다.
ViewModel은 Activity/Fragment의 UI에 표시되는 데이터를 저장, 관리한다. 그렇기 때문에 관련 함수들을 ViewModel에 작성하게 된다. 하지만 모든 데이터를 저장하면 안 된다. UI복원에 필요한 데이터들만 보관해야 한다. '커니의 코틀린'(책)에 나온 예를 인용해보겠다. "데이터베이스에 있는 정보를 리스트에 표시하는 경우라면, 현재 화면에 보여지고 있는 리스트는 전체 데이터 중 일부 데이터 일 수 있다. 이때, ViewModel 클래스에는 현재 표시되고 있는 '일부'데이터를 복원할 수 있는 정보만 저장해야 한다." 라고 되어있다.
결론
Android에서 생명주기 관리와 함께 상호 의존성을 낮추어 주기 위해 MVVM패턴을 이용하면 좋고, 이 때 Android에서 제공하는 ViewModel 컴포넌트를 사용하면 패턴 구현에 도움이 될 수 있다. 추가적으로 의존성 관리를 위해 이 패턴과 함께 사용할 수 있는 Dagger 라이브러리를 사용하여 의존성 주입을 구현해 좀 더 깔금한 앱이 될 수 있다.
'Android' 카테고리의 다른 글
RecyclerView에 줄 라인 추가하기(Divider) (0) | 2020.07.27 |
---|---|
Layout Inspector로 레이아웃 디버깅하기 (0) | 2020.06.01 |
Android 아키텍처 컴포넌트를 사용한 구조 개선 (0) | 2020.04.03 |
'onMessageReceived' overrides nothing 해결 (1) | 2020.03.30 |
Biometric을 이용한 지문 인식 사용 (2) | 2020.03.20 |
댓글
이 글 공유하기
다른 글
-
RecyclerView에 줄 라인 추가하기(Divider)
RecyclerView에 줄 라인 추가하기(Divider)
2020.07.27 -
Layout Inspector로 레이아웃 디버깅하기
Layout Inspector로 레이아웃 디버깅하기
2020.06.01 -
Android 아키텍처 컴포넌트를 사용한 구조 개선
Android 아키텍처 컴포넌트를 사용한 구조 개선
2020.04.03 -
'onMessageReceived' overrides nothing 해결
'onMessageReceived' overrides nothing 해결
2020.03.30