요즘 기업에서 안드로이드 직군 자격요건&우대사항을 뒤져보면 MVVM을 다루본 개발자를 찾는 경우가 많은데 트민녀인 나는 또 그냥 지나칠 수가 없었다ㅎㅎ 또 작년엔 디자인패턴 공부도 열심히 했기 때문에 새로운 패턴에 관심도 많이 갔다.
그런데 MVC 패턴도 제대로 써본 적 없는 내가 글만 보고 MVVM 패턴을 단박에 이해하기란 쉽지 않았다. 그래서 MVVM 관련 블로그도 있는대로 찾아서 읽고 또 읽었고, 블로그 코드들을 참고하며 냅다 프로젝트에 적용해 보았다.
그러다 크나큰 실수를 저지르게 되었는데....
바로 사실 내가 MVVM 패턴을 사용한 것이 아니라 단지 AAC의 ViewModel을 사용했다는 것이다.
아마 나같은 실수를 하는 사람이 굉장히 많을 것이다. 많은 블로그에서 정확하게 명명하고 있지 않기 때문에 자칫하면 나가리다(?)
더 많은 개발자들이 MVVM 패턴에 대한 제대로 된 포스팅을 해야 혼란을 막을 수 있다고 생각하기 때문에 나또한 이 글을 쓰게 되었다.
MVVM 패턴 ?
MVVM 패턴은 기존의 MVC 패턴처럼 액티비티/프래그먼트에 모든 앱 동작을 위한 코드가 몰리는 구조를 피하고
체계적인 구조와 유지보수 효율성 등을 높이기 위해 제안된 패턴이다.
나또한 경진대회에 나가 수상에 눈이 돌아 동작하기만 하면 장땡이라는 마인드로 처음 앱을 개발했을 때가 있었다.
그냥 액티비티 하나에서 json 파일 받아서 파싱하고 그때그때 뷰에 세팅해주고, 진짜 개노답 코딩을 했었다. (MVC도 아니고 뭣도 아님ㅎ)
대부분의 블로그에서 MVC 를 알고 있다는 가정하에 MVC 와 MVVM을 비교하는 식으로 정리하는데 사실 나는 MVC도 뭔지 모르는 사람이었다. 그래서 이 김에 MVC도 공부해봤다...
MVC
MVC는 아래와 같은 구조의 패턴으로 controller, view, model로 구성되어 있다.
Model -> 데이터와 관련된 객체 클래스들을 이야기 하는 것 같다.
예를 들어 사용자 정보를 가져온다면 User 클래스를 미리 정의해놓고 서버로부터 데이터를 받아 객체 인스턴스를 생성해 데이터들을 세팅하는 메서드를 갖을 수 있다.
View -> 화면에 나타나는 UI를 그린다.
예를 들어 controller에서 사용자의 정보를 그리라는 메서드를 호출하면 화면에서 참조하고 있던 (업데이트된)User 객체를 사용해 화면을 그린다.
Controller -> 사용자의 입력을 받거나 필요시 model의 데이터를 갱신을 요청하거나, view의 UI 갱신을 요청한다.
예를 들어 사용자가 회원가입을 요청하면 User 객체를 만들고 정보 세팅/업데이트를 요청한다. 그리고 view에 정의된 사용자 정보 그리기 메서드 등을 요청할 수 있을 것이다.
[참고 코드] *gpt
딱 봐도 controller는 중간에 껴서 model에 데이터 업데이트 요청하랴, view에 UI 업데이트 요청하랴 굉장히 바쁘다.
그리고 view의 경우 반드시 자신의 UI갱신에 필요한 model 객체를 참조하고 있어야 하기 때문에 view-controller 사이의 의존도가 높아질 수 밖에 없다.
또한 MVC 패턴은 메모리 누수에도 취약할 수 있다고 한다. 이게 무슨 소린가 하니....
아마 더보기 코드를 보면 알겠지만 서로간에 참조하는 경우가 많다 보니 액티비티에서 view를 더이상 사용하지 않는 경우, view에서 model을 더이상 사용하지 않는 경우 해제가 제대로 되지 않으면 메모리 누수가 발생할 수 있다는 의미 같다.
MVVM
이런 단점을 보완하기 위해 controller의 동작을 분리하고, 흐름 자체를 더욱 체계적으로 만들어 주는 방법이 바로 MVVM 패턴이다.
ViewModel을 통해 view 와 model 사이의 중재자 역할을 하면서 view 에 필요한 데이터를 관리하는 역할을 한다.
MVVM 패턴의 특이점이자 MVC와 다른점은 ViewModel이 view를 몰라야 하기 때문에 직접 view에 UI 갱신 요청을 하지 않는다.
대신 서로 데이터바인딩 이라는 결합을 통해 데이터의 변화를 감지하고 UI 에 반영하게 된다.
적절한 ViewModel이 있다면 여러개의 View에서 같은 ViewModel 클래스를 이용할 수도 있다. 그래서 ViewModel:View = N:1 관계이다.
추가적으로 이와 관련해서 Naver Grab 에서 진행한 강연을 봤었는데 정리한 내용은 아래와 같다.
MVVM 은 아래 3가지 조건을 만족해야 한다.
- View-ViewModel 연결 최소화
- ViewModel 은 데이터의 변화를 View에 전달, 데이터를 관리
- View 는 화면 정보의 변화를 ViewModel 에 전달
*이때 View는 XML 이지 Activity/Fragment가 아니다
=> View-ViewModel 서로가 서로를 알지 못해야 하는데 사실상 불가능 하기 때문에 Databinding을 사용
=> Databinding은 build 이후에 생성되는 setter() 메서드를 사용해서 View(XML)의 데이터를 ViewModel에 세팅해주는 것이다.
하지만 현실적으로 안드로이드 개발에서 Databinding 만을 이용해서 View-ViewModel가 완벽하게 독립적인 MVVM 을 구현하기에는 어려움이 있을 수 있다.
1. LifeCycle
2. Databinding만으론 모두 표현하기 힘든 View 이벤트
3. Resource등 Context 를 접근해야 하는 경우
그 이유로 위와 같은 3가지 이유를 소개해주셨고, 대표적인 예가 화면 회전시 화면이 갱신되면서 데이터 도한 유지되지 못하고 초기화 되는 그런 문제점들일 것 같다.
이런 문제를 해결하기 위해서 네이버의 grab에서는 다양한 방법을 강구하고, 자신들에게 맞는 커스텀 코드를 작성해 관리하는 것 같다. (그만큼 제대로 된 MVVM 사용에 진심이신 분들...)
[참고]
https://stickode.tistory.com/267
https://tv.naver.com/v/4637223?query=mvvm&plClips=false:4637223:3547873:3390780:4635548
처음 MVVM 패턴에 대해 공부했을 때는 그냥 ViewModel이 중간다리 역할을 한다~ 정도만 이해를 했었다.
참고했던 블로그에서도 MVVM 구조에 대해서만 간략하게 설명하고 갑자기 구글에서 제안한 AAC 의 ViewModel을 사용해 MVVM 패턴을 구현할 수 있다고 전개했기 때문에 그런가 보다 했고.... 그렇게 불행의 서막이 시작되었다.........
AAC ViewModel / MVVM ViewModel / ACC MVVM
AAC(Android Architecture Component)는 테스트와 유지보수가 쉬운 앱을 디자인할 수 있도록 돕는 라이브러리 모음을 말한다.
ViewModel, LiveData, ROOM 과 같은 라이브러리가 이에 해당한다. (구글이 제안)
여기서 ViewModel은 안드로이드 수명주기를 고려하여 UI관련 데이터를 저장하고 관리한다.
예를 들어 앱 화면 전환을 하게 되면 뷰들이 다시 그려지는데 그러면서 이 뷰들을 참조하고 있던 데이터들도 다시 초기화가 되는 것이다.
이를 방지 하기 위해 ViewModel은 View가 완전히 Finished된 이후 비로소 clear() 하기 때문에 초기화 되지 않고 데이터를 보존할 수 있다.
**제발 주의하자 !!!!!!***
AAC의 ViewModel은 MVVM의 VIewModel과 완전히 다르다.
'데이터를 관리한다' 라는 역할은 비슷할 수 있지만 그냥 이름만 같지 동일인물이 아니란 말이다!!!!!!
💢 나의 오해
근데 자꾸 블로그들이 AAC 의 ViewModel을 사용해서 MVVM 을 구현할 수 있다고 말한다.
틀린 말은 아니지만 오해의 소지가 다분한 면이 있다....
AAC의 ViewModel을 사용해 MVVM 을 구현할 수 있다고 하니까 "아, MVVM 패턴 구현하려면 AAC의 ViewModel 사용하면 되는거구나~" 하는 사람들이 너무 많다.
나도 처음엔 AAC 자체가 처음부터 MVVM 패턴을 염두에 두고 MVVM 패턴을 사용하기 쉽게 하기 위해 해당 패턴을 적용해 만들어진 구조, 라이브러리들이라고 생각했었다.
보통 블로그들에도 AAC ViewModel을 사용해 MVVM 을 구현했다는 예제들을 보면 ViewModel에 LiveData 정의하고, 액티비티에서 LiveData를 Observe 하고 있다.
하지만 이렇게 액티비티에서 뷰모델의 데이터를 옵져빙 하고 있는 것 자체가 MVVM 이 아니다....
그리고 꼭 함께 나오는 구조 그림이 있는데...
괜히 이 그림을 보고
"아 MVVM 구현하려면 이 구조대로 프젝 만들고 액티비티에서 뷰모델의 라이브데이터 옵져빙 하면 mvvm 패턴 뚝딱이구나~"
하면 안 된다....
이 그림은 그냥 AAC에서 제안하는 앱개발의 효율성과 유지보수를 편리하게 하기 위해 구글이 제안하는 SW설계 "아키텍쳐" 이다.
그 안에서 지들이 또 제공하는 viewmodel, livedata, room 같은 라이브러리를 이런 구조로 적용할 수 있다는 것이다.
애초에 AAC는 테스트와 유지보수 편리성을 위해 구글에서 제안하는 아케텍쳐이지 처음부터 MVVM 을 고려하고 만든 구조가 아니라는 것이다!!! 단순히 AAC의 구성 요소가 MVVM 패턴과 잘 호환되었기 때문에 MVVM 패턴 구현에 활용되는 것일 뿐이다.
AAC에서 ViewModel을 사용해 MVVM 을 구현하려면 마찬가지로 Databinding 을 사용해야 한다.
물론 이 과정에서 LiveData 등의 라이브러리가 사용될 수 있다. LiveData 자체는 화면 변화에서 생명주기에 영향을 받지 않고 데이터를 보존해주는 역할을 하기 때문이다.
대신 이 LiveData를 observing 하는 방식으로 사용해서는 안 된다는 것이다.
[AAC의 ViewModel 과 LiveData, Databinding을 함께 사용하는 코드]
https://develop-writing.tistory.com/45
MVVM도 제대로 구현하면서 AAC 라이브러리들도 사용하는 것이 쉬운일은 아닌 것 같다. 중간에 라이브러리를 사용하면서 MVVM 패턴이 깨질 수도 있고 이런 경우 구조 박살(?)에 대한 예외를 두거나 네이버 Grab 처럼 자체적으로 보완해주는 코드를 짜야할 수도 있다.
그렇기 때문에 MVVM 패턴을 사용한다는 것은 굉장히 까다로운 고급 스킬이고 더 복잡해질 수 있다.
큰 프로젝트에서 효율성과 유지보수를 위해 사용하기 때문에 굳이 작은 규모의 프로젝트에서 초보자가 썼다가는 괜히 개고생하고 나처럼 잘못 써서 나중에 망신을 당할 수도 있다....ㅎㅎ
물론 나의 집착광공적인 면모로 끊임없이 의심해서 다시 공부하고 제대로 알아갈 수 있었지만....
AAC과 AAC를 활용한 코드, AAC ViewModel 을 활용해 제대로 MVVM을 구현하는 내용의 포스팅은 따로 올려보겠다.
[참고]
https://wooooooak.github.io/android/2019/05/07/aac_viewmodel/
https://velog.io/@min0505/Android-%EA%B0%9C%EB%85%90-AAC-ViewModel-MVVM-ViewModel
요약
AAC ViewModel 을 사용했다 -> 무조건 MVVM 이 구현된 것이다 (X)
AAC ViewModel 을 사용해서 MVVM 을 구현할 수 있다 (O)
AAC ViewModel 을 사용해서 MVVM 을 구현하려면 DataBinding을 사용해야 한다 (O)
AAC ViewModel 을 사용해서 MVVM 을 구현할 때 액티비티에서 뷰모델의 LiveData를 observing 하도록 한다 (X)
MVVM 을 구현한다
- View - ViewModel 간의 연결을 최소화 한다
- DataBinding를 사용해야 한다
AAC ViewModel 을 사용한다
- 안드로이드의의 라이프사이클 특성을 고려하여 데이터를 효율적으로 관리한다.
[추가 공부용 자료]
https://www.youtube.com/playlist?list=PLRRNzqzbPLd906bPH-xFz9Oy2IcjqVWCH
https://github.com/android/architecture-samples/branches/stale
'Android' 카테고리의 다른 글
[안드로이드/아키텍쳐] 안드로이드 공식 권장 아키텍쳐 (구vs신버전) (0) | 2023.07.19 |
---|---|
[안드로이드/아키텍쳐] AAC ViewModel 사용하기 (0) | 2023.07.13 |
[안드로이드/Activity] Parcelable, Serializable 그리고 Parcelize (1) | 2023.07.13 |
[안드로이드/소셜로그인&Oauth] AWS와 통신하는 안드로이드 앱에서 Google Oauth2.0 사용하기 (4) | 2023.07.13 |
[안드로이드/센서] GPS 사용하기 (0) | 2023.05.16 |