MVVM 패턴이란?
코드를 Model, View, ViewModel의 역할에 맞게 분리하서 작성하는 디자인 패턴
왜 MVVM을 사용할까?
1. 사용안하면 뭐 어쩔건데?
MVVM 패턴
을 사용하지 않고 액티비티/프래그먼트
에 모든 코드를 넣게 되면 어떻게 될까요?
액티비티/프래그먼트
코드가 매우 복잡해짐스파게티 코드가 될 확률이 높아짐
유지보수 & 테스트가 어려워짐
다른 사람이 코드를 이해하기 어려워짐 (본인 포함)
이런 단점이 있기 때문에 코드를 분리해서 작성하는 MVVM 패턴
을 사용한다.
2. MVVM말고 다른 패턴(MVC, MVP)를 사용하면 안되나요?
MVC
의 경우 Model, View, Controller로 코드를 관리
하지만 View와 Model 사이의 의존성이 높다는 단점이 있다.
MVP
의 경우 Model, View, Presenter로 코드를 관리
하지만 View와 Presenter 사이의 의존성이 높다는 단점이 있다.
아니 ... 의존성은 또 뭐고 그게 높으면 뭐 어떻게 되는데요??? -> 이거 ... 보고 오시죠!
-> MVVM > (MVC, MVP)
3. 협업이 쉬워짐
(다른 디자인 패턴도 마찬가지이지만) 팀원들이 전부 MVVM 패턴
을 적용하고 이해하고 있으면 개발 커뮤니케이션이 수월해진다!
4. 그리고 ...
각각의 부분이 독립적 -> 유닛 테스트 용이
모듈화가 잘 되어 있다면 내장 DB를 통채로 변경하는게 비교적 쉬움 ex) realm -> room
ViewModel
과View
가 1:n 연결이 가능 -> 뷰모델 재활용 가능View
가 데이터를 실시간으로 관찰하고 자동으로 UI 갱신
자세히 알아보자!
구조
Model
- 어플리케이션에서 사용하는 데이터와 그 데이터를 처리하는 부분
View
액티비티/프래그먼트, 사용자에게 보여지는 UI
사용자와 상호작용
ViewModel
의 데이터를 관찰하여 UI 갱신ViewModel
Model
과View
를 이어주는 역할.Model
의 데이터를 가공하여View
에게data stream
을 제공
어떻게 구현?
AAC(Android Architecture Components)를 사용하면 비교적 쉽게 구현 가능
AAC
- 강력하고 테스트와 유지관리가 쉬운 앱을 디자인하도록 돕는 라이브러리 모음
주로 안드로이드 MVVM 패턴
에는 AAC
의 LiveData
와 ViewModel
을 사용한다.
주의사항
1. AAC의 ViewModel != MVVM의 ViewModel
어 뭐야? 둘이 같은거 아닌가요??? -> 아뇨 ... 이름만 같아요 ... ㅋㅋㅋ
AAC ViewModel
ViewModel
클래스는 수명 주기를 고려하여 UI 관련 데이터를 저장하고 관리하도록 설계되었습니다.ViewModel
클래스를 사용하면 화면 회전과 같이 구성을 변경할 때도 데이터를 유지할 수 있습니다. - 공식 문서MVVM ViewModel
Model
과View
를 이어주는 역할.Model
의 데이터를 가공하여View
에게data stream
을 제공
그러면 어떻게 AAC ViewModel
을 MVVM ViewModel
처럼 사용하느냐...! 단순히 AAC ViewModel이 가지고 있는 데이터를 관찰가능하게 해주고 View는 데이터바인딩으로 그것을 구독하고 있으면 된다! 이렇게 하면 데이터를 수명 주기를 고려하여 관리할 수 있으므로 더 좋다!
하지만 단점도 있다.AAC ViewModel
은 액티비티
에 단 하나만 존재할 수 있다. 예를 들어 MainViewModel
을 한번 생성하면 그 액티비티
에서 MainViewModel
을 여러번 생성해도 하나의 객체만 사용된다. MVVM 패턴
은 View
와 ViewModel
이 1:n 관계인데, AAC ViewModel
은 이를 지킬 수 없다. 또한 구글은 View
와 AAC ViewModel
을 1:1 관계로 사용하고 ViewModel
안에 여러 Model
과 LiveData
를 사용하도록 권장한다. 이 역시 MVVM
원칙을 위반한다.
2. LiveData의 한계
우선 LiveData
가 뭔지 알아보자.LiveData
란 LiveCycle
을 알고 있는 DataType
이라 생각하면 된다. LiveData는 Observer 객체를 이용하여 데이터의 변화를 관찰하며 UI를 업데이트 합니다. 어라? MVVM
에서 View
의 역할은 ViewModel의 데이터를 관찰하여 UI를 갱신하는건데 ... 아! ViewModel
의 데이터를 LiveData
로 만들면 되겠네!
LiveData vs MutableLiveData
LiveData
는 read-only
이고 MutableLiveData
는 LiveData
를 수정할 수 있다.ViewModel
를 캡슐화 하기위해 외부로 노출되는 값인 read-only
LiveData
를 public
으로 내부에서는 데이터를 편집할 수 있는 MutableLiveData
를 private
로 만들자!
캡슐화를 하는 이유
데이터 내용을 변경할 수 있는 기능을 외부로 노출하면 디버그하기 어렵고 데이터의 내용이 어디서 왔는지 추론하기 어려워지기 때문 다른 이유는 링크 참고
그래서 LiveData
의 한계가 뭔데?
바로 비동기 데이터 스트림을 지원하지 않는다는 것! 이유는 LiveData
는 UI와 밀접하게 연관되어 있기 때문에 오직 Main Thread
에서만 관찰되기 때문이다. 따라서 데이터베이스(Local)과 서버(Remote)와의 통신이 이루어지는 Repository
에서 LiveData
를 사용할 수 없다.
클린 아키텍처의 Domain Layer
에서도 LiveData
를 사용할 수 없다. Domain Layer
는 순수 Java 및 Kotlin 코드로만 구성하는데 LiveData
는 안드로이드 플랫폼에 종속적이기 때문
이러한 이유로 LiveData
는 사용하지 않는게 좋다! (Repositroy
는 해당 포스트에서 클린 아키텍처는 나중 포스트에서 다룰 예정)
Flow
하지만~!! 비동기 데이터 스트림을 지원하는 Kotlin 클래스 Flow
가 존재한다. 이를 통해 ViewModel
에서는 LiveData
를 사용하고 DB, 서버와 통신을 하는 Repository
같은 곳에서는 Flow
를 사용하면 된다. 하지만 ... 이런 방법을 사용해도 Flow
는 LiveData
를 완전히 대체할 수 없다.
Flow
는 스스로 안드로이드 생명주기에 대해 알 수 없다.Flow
는 상태가 없어 값이 할당된 것인지, 현재 값은 무엇인지 알기가 어렵다.Flow
는Cold Stream
방식으로, 연속해서 계속 들어오는 데이터를 처리할 수 없으며collect
되었을 때만 생성되고 값을 반환한다. 만약, 하나의flow builder
에 대해 다수의collector
가 있다면collector
하나마다 하나씩 데이터를 호출하기 때문에 업스트림 로직이 비싼 비용을 요구하는 DB 접근이나 서버 통신 등이라면 여러 번 리소스 요청을 하게 될 수 있다.
StateFlow, SharedFlow
위의 단점을 보완하기 위해 StateFlow
, SharedFlow
가 나왔다. (SharedFlow
는 StateFlow
의 일반적인 버전이다. 자세한 설명은 다른 포스트에서 하겠다.)
StateFlow 특징
StateFlow
는 항상 값을 가지고 있고, 오직 한 가지 값을 가진다.StateFlow
는 여러 개의collector
를 지원한다. 이는flow
가 공유된다는 의미이며 앞서 설명했던flow
의 단점과는 다르게 업스트림이collector
마다 중복으로 처리되지 않는다.StateFlow
는collector
수에 관계없이 항상 구독하고 있는 것의 최신 값을 받는다.StateFlow
는flow builder
를 사용하여 빌드된flow
가cold stream
이었던 것과 달리,hot stream
이다. 따라서collector
에서 수집하더라도 생산자 코드가 트리거 되지 않고, 일반flow
는 마지막 값의 개념이 없었던 것과 달리StateFlow
는 마지막 값의 개념이 있으며 생성하자마자 활성화된다.
LiveData
는 StateFlow
로 완전히 대체 가능하다.
Repository 패턴
아! 이제 MVVM을 사용하는 이유, 기본 개념, AAC ViewModel과 MVVM ViewModel의 차이점, LiveData대신 StateFlow를 사용해라! 까지 알았으니 이제 실습만 하면 되겠군요? ㅋㅋ
아뇨 Repositroy 패턴까지만 ... 보고 가시죠!
Repositroy
데이터 출처(로컬 DB인지 API응답인지 등)와 관계 없이 동일 인터페이스로 데이터에 접속할 수 있도록 만드는 것을 Repository 패턴이라고 한다. 레포지토리는 데이터 소스에 액세스하는 데 필요한 논리를 캡슐화하는 클래스 또는 구성 요소이다. Repository 의 존재 덕분에 ViewModel 이 데이터를 관리할 필요가 없게 된다.
마무리
이렇게 Repository에 대한 간단한 설명을 마지막으로 포스팅을 끝내려한다. 이제 남은 일은 Github에서 MVVM 예제 소스를 찾아서 공부하는 것 뿐 ... (클린 아키텍처도 공부 ...)
레퍼런스
https://velog.io/@haero_kim/Android-%EA%B9%94%EC%8C%88%ED%95%98%EA%B2%8C-MVVM-%ED%8C%A8%ED%84%B4%EA%B3%BC-AAC-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0
devvkkid.tistory.com/196
readystory.tistory.com/207
yjyoon-dev.github.io/android/2022/02/12/and..
velog.io/@k7120792/Model-View-ViewModel-Pat..
leveloper.tistory.com/216 https://blog.yena.io/studynote/2019/03/16/Android-MVVM-AAC-1.html