디자인 패턴 관련 글 첨부합니다.
2024.04.30 - [안드로이드] - [Android] 디자인 패턴 이해 (MVC/MVP/MVVM)
[Android] 디자인 패턴 이해 (MVC/MVP/MVVM)
1. 디자인 패턴이란?객체 지향 프로그래밍을 설계할 때 자주 발생하는 문제에 대응하기 위해서 사용되는 패턴을 의미한다.어떻게 보면 개발하는 방법을 공식화한 것이라고 생각하면 된다. 2.
goharry.tistory.com
2024.05.04 - [안드로이드] - [Android] MVC 패턴!
[Android] MVC 패턴!
2024.04.30 - [안드로이드] - [Android] 디자인 패턴 이해 (MVC/MVP/MVVM) [Android] 디자인 패턴 이해 (MVC/MVP/MVVM)1. 디자인 패턴이란?객체 지향 프로그래밍을 설계할 때 자주 발생하는 문제에 대응하기 위해서
goharry.tistory.com
2024.08.17 - [안드로이드] - [Android] MVP 패턴!
[Android] MVP 패턴!
디자인 패턴 관련 글들을 첨부하고 시작하겠습니다.2024.04.30 - [안드로이드] - [Android] 디자인 패턴 이해 (MVC/MVP/MVVM) [Android] 디자인 패턴 이해 (MVC/MVP/MVVM)1. 디자인 패턴이란?객체 지향 프로그래밍
goharry.tistory.com

1. MVVM 패턴이란?
위키피디아에서는 이렇게 정의하고 있습니다.
모델-뷰-뷰 모델(model-view-viewmodel, MVVM)은 하나의 소프트웨어 아키텍처 패턴으로 마크업 언어 또는 GUI 코드로 구현하는-그래픽 사용자 인터페이스(뷰)의 개발을 비즈니스 로직 또는 백-엔드 로직 (모델)로부터 분리시켜서 뷰가 어느 특정한 모델 플랫폼에 종속되지 않도록 해준다.
2. Model, View, ViewModel의 동작

- 사용자의 입력이 View를 통해 들어옴
- View는 동작에 맞는 data를 ViewModel에게 요청
- ViewModel은 Model에게 데이터를 요청
- Model은 요청받은 데이터를 응답
- ViewModel은 관찰가능한 Filde로 매핑해서 외부로 노출
- View는 ViewModel을 관찰해서 자신을 변경
3. 구성요소의 역할
1. Model
앱 내에서 필요한 데이터, 상태, 비즈니스 로직을 저장하고 처리하는 역할
2. View
사용자가 직접 보는 UI를 담당
3. ViewModel
View와 Model 사이에 위치하여 중재하는 역할. View와 데이터바인딩을 통해 서로 연결한다.
데이터 변경이 발생하면 Model을 갱신하거나 가져와서 View에 필요한 Observable Data로 가공
4. MVVM 패턴의 장단점
1. 장점
- View와 ViewModel 사이의 의존성이 없다.
2. 단점
- ViewModel의 설계가 어렵다.
5. 예제
https://github.com/eukkbro/designPattern
GitHub - eukkbro/designPattern
Contribute to eukkbro/designPattern development by creating an account on GitHub.
github.com
예제 간단 설명
바텀내비게이션으로 각각의 프래그먼트를 mvc, mvp, mvvm 패턴으로 동작하게 만들었습니다.
버튼을 클릭하면 랜덤 한 고양이 사진이 나오는 예제입니다.
따라서, MVVM 패턴 관련 부분만 작성하겠습니다.
편한 구현을 위해서 데이터 바인딩을 사용했습니다.
1. View (MVVMFragment)
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="abled.semina.designPattern.mvvm.ViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".mvvm.MvvmFragment"
android:padding="20dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:scaleType="fitCenter"
android:src="@drawable/ic_launcher_background" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="@string/another"
android:onClick="@{()->viewModel.setOnButtonClick()}"
style="@style/button_normal"
/>
</LinearLayout>
</layout>
class MvvmFragment : Fragment() {
private val TAG = "mvvm 프래그먼트"
private lateinit var binding: FragmentMvvmBinding
private var viewModel:ViewModel = ViewModel()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
/**데이터 바인딩**/
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_mvvm, container, false)
/**초기화 설정**/
setInitialize()
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
/**옵저버 셋팅**/
setObserve()
}
private fun setInitialize(){
/**라이프사이클오너를 프래그먼트로 설정**/
binding.lifecycleOwner = this
/**xml에 사용할 뷰모델 설정**/
binding.viewModel = viewModel
}
private fun setObserve(){
/**뷰모델의 randomCatUrl을 관찰**/
viewModel.randomCatUrl.observe(viewLifecycleOwner){
Log.d(TAG, "뷰모델의 url 데이터 관찰")
/**관찰한 값을 글라이드를 통해 이미지 뷰에 띄우는 메서드**/
setImageView(it)
Log.d(TAG, "관찰해서 view를 변경")
}
}
private fun setImageView(url: String){
Log.d(TAG, "View : 관찰한 url 값을 Glide를 통해 이미지뷰에 띄우기")
/**글라이드**/
Glide.with(this)
.load(url)
.placeholder(R.drawable.loading)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(binding.imageView)
}
}
2. ViewModel
버튼을 클릭하면 모델에 있는 랜덤 고양이 url을 요청해서 observable filde로 매핑합니다.
setOnButtonClick 메서드는 xml파일의 <Button>에서 onClick에서 호출되고 있습니다.
class ViewModel: ViewModel(){
private val TAG = "mvvm 뷰모델"
private var model = Model()
private val _randomCatUrl = MutableLiveData<String>()
val randomCatUrl: LiveData<String>
get() = _randomCatUrl
fun setOnButtonClick(){
Log.d(TAG, "viewModel : model에게 url 요청")
_randomCatUrl.value = model.getCatUrl()
}
}
3. Model
랜덤한 고양이 사진을 보여주는 url을 getCatUrl을 통해 반환합니다.
class Model {
private val TAG = "mvvm 모델"
private var randomCatUrl = "https://cataas.com/cat?type=square"
fun getCatUrl(): String{
Log.d(TAG, "모델 : ${randomCatUrl}을 반환")
return randomCatUrl
}
}

정리
앞선 글에서 MMVP 패턴 보다 먼저 MVVM 패턴 적용을 해서 연습을 많이 해봐서 MVVM 패턴의 설계가 더 쉽다고 생각했는데 복잡해질수록 MVVM 패턴의 설계가 더 어려워질 것 같긴 하다.
그래도 데이터바인딩과 observe 패턴을 쉽게구현하게 도와주는 Livedata를 함께 사용해서 뷰와 뷰모델간의 의존성을 더욱 최소화시킬 수 있는 점이 재밌었다.
끝!
'안드로이드' 카테고리의 다른 글
[Android] Activity Lifecycle (1) | 2024.11.08 |
---|---|
[Android] 기본 스플래시 없애기 (0) | 2024.08.21 |
[Android] MVP 패턴 예제! (0) | 2024.08.17 |
[Android] Glide 3 - 원형 이미지에 로딩 애니메이션 구현 (4) | 2024.07.29 |
[Android] Glide 2 - 로딩 애니메이션 구현 (0) | 2024.07.27 |