MVVM 패턴에 대하여
Updated:
-
MVVM
-
안드로이드에 대해 더 공부하고 개발하다 보니 현재 다양한 곳 에서 쓰이고 있는
MVVM
패턴에 대해서 정리해보고자 한다. 처음 접한 것은 코틀린으로 쇼핑몰 앱 만들기 라는 책에서 처음 접해봤으며 한 Fragment나 Activity에 모든 기능과 소스들을 때려박았던 것 보다 훨씬 유용하다고 생각했고 좀 더 자세히 공부해 보고 싶어서 글을 쓰게 되었다.아직 많이 미숙하지만 내가 여러 블로그와 구글링을 해서 얻어온 정보를 정리하고자 하는 것이니, 누군가 이걸 본다면 그냥 참고용으로만 봐 주었으면 좋겠다.
앱 아키텍처는 나중에 다뤄 보고 일단은 MVVM에 대해서 정리해보겠다.
-
-
MVVM - Model-View-ViewModel의 줄임말, 하나의 소프트웨어를 최대한 작은단위로 나누어 유지보수가 용이하게 만든 구조.
Input들은 View로 전달되어, ViewModel은 Input에 해당되는 Logic을 처리, View에 data를 전달하는 방식이고 ViewModel과 View는 독립적이며
ViewModel : View = 1:N
관계를 가진다. -> View가 자신이 사용할 ViewModel을 선택해 바인딩하여 받는 형태이다.나중에 Model이 상태 및 데이터들이 변경될 때 해당 ViewModel을 사용하는 View가 자동적으로 업데이트 됨.
MVP와 마찬가지로 M-V사이에 의존성이 없고, V-VM이 독립적이다.
-
기본적인 MVVM 구조 - (출처 : 위키백과)
-
-
View - UI를 담당하는 Activity나 Fragment 등을 정의. 화면에 나타나는 것이고, 사용자와 상호작용한다.
- 예시 - ShoppingMall App의 ProductMainActivity - UI는 따로 정의 하였다.
class ProductMainActivity : BaseActivity<ProductMainViewModel>() { override val viewModelType = ProductMainViewModel::class private val ui by lazy { ProductMainUI(getViewModel()) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ui.setContentView(this) ui.viewPager.adapter = ProductListPagerAdapter(supportFragmentManager) ui.tablayout.setupWithViewPager(ui.viewPager) setupDrawerListener() } private fun setupDrawerListener() { val toggle = ActionBarDrawerToggle( this, ui.drawerLayout, ui.toolbar, R.string.open_drawer_description, R.string.close_drawer_description ) ui.drawerLayout.addDrawerListener(toggle) toggle.syncState() } }
-
ViewModel - View에 연결된 데이터 및 관련 로직이 들어가고, 데이터를 잘 가공하여 View에 뿌리기 쉬운 Model로 바꾸는 역할을 하고, 변경알림 이벤트를 통해 상태 변경을 View에게 알림. 또한 View와 분리 되어있기 때문에 View가 Destroy 되어 다시 Create가 되어도 데이터를 여전히 가지고있는다.
- 예시 : ProductMainViewModel
class ProductMainViewModel(app: Application) : BaseViewModel(app) { fun openSearchActivity(keyword:String?){ keyword?.let{ startActivity<ProductSearchActivity>{ putExtra(ProductSearchActivity.KEYWORD, keyword) } }?:toast("검색 키워드를 입력해주세요.") } fun openRegistrationActivity() { startActivity<ProductRegistrationActivity>() { flags = Intent.FLAG_ACTIVITY_SINGLE_TOP } } }
-
Model - 사용하려는 데이터를 가지는 클래스로 DTO, POJO, ENTITY 개체 등이 있다. 일반적으로 데이터를 액세스 하거나 캐싱이 필요한
Service
orRepository
와 함께 사용됨. (Source Code - Category, ViewModel)- 예시 :
Category
의 categoryList를ProductRegistrationViewModel
에서 사용하는 예시
class ProductRegistrationViewModel(app: Application) : BaseViewModel(app){ //... val categories = MutableLiveData(categoryList.map { it.name }) var categoryIdSelected: Int? = categoryList[0].id //... fun onCategorySelect(position: Int) { categoryIdSelected = categoryList[position].id } //... } //Catogory.kt data class Category( val id: Int, val name: String ) val categoryList = listOf( Category(0, "여성의류"), Category(1, "남성의류"), Category(2, "가전제품"), Category(3, "생활용품"), Category(4, "도서"), Category(5, "반려동물용품"), Category(6, "식품") )
- 예시 :
-
결론
- 장점 : 각 사이의 의존성이 없어서 유지 보수가 용이 한것이 사실이고, 변수들이 제대로 설정되어있는지 여부도 확인하기 용이하다. 또한 중복 코드를 모듈화 하여 효율적으로 코딩이 가능하다.
- 단점 : ViewModel 설계가 어려운것 같다. 하지만 사실 내가 코딩 실력이 부족해서 어렵게 느껴지는 것 같다.
- 앞으로 추가적인 안드로이드 디자인 패턴에 대해 공부를 해야겠지만 여러 디자인 패턴중에 이것이 완벽한 정답이다 라고 느껴지는 건 없는 것 같다. MVC, MVP 패턴을 앞으로 포스팅하며 잘 익혀봐야할 것 같고 MVVM 구조를 활용한 추가적인 예제 어플을 제작하기로 했다.