[디자인 패턴] MVVM에 대한 공부 (+DataBinding)

colins·2023년 2월 25일
1

이미 MVVM 패턴을 비롯한 여러 디자인 패턴이 나와있는 상황에서 MVVM에 대한 설명보다는 이를 개인적으로 공부하며 배운 점을 정리하기 위해 작성하였다.



1. MVVM 패턴을 사용할 경우의 이점

1) UI와 로직을 분리
2) ViewModel이 데이터를 가지고 있음


UI와 로직을 분리했을 때의 이점은 무엇일까?

View(Activity, Fragment 등)에서는 데이터 처리 로직을 신경써도 되지 않고,
UI의 업데이트에만 신경쓰면 되니 유지보수에 용이하다.

또한 ViewModel이 데이터를 가지고 있고, View와 Model이 서로 독립성을 유지하게 하며, memory leak가 발생하지 않는다.




2. MVVM 패턴의 구동 방식

MVVM은 그림처럼 ViewModel을 사용해서 Model과 View를 분리시켜 서로의 의존성을 낮추기 위해 사용하는 디자인 패턴이다.

사용자가 View(Activity/Fragment) 내 Button, Textview 등의 동작을 요청하였을 때, Viewmodel이 Model 클래스에 데이터 갱신을 요청하게 되고, View에서는 갱신된 데이터를 받은 ViewModel을 LiveData를 통해 observe하고 있기 때문에 갱신된 데이터를 받을 수 있게 된다.

보통 ViewModel은 Recyclerview를 이용할 때, LiveData, Databinding과 함께 사용하는 경우가 많은데 Databinding을 통해 Recyclerview의 ViewHolder class 내 코드를 단순화할 수 있다.




3. MVVM의 실 사용 예


-추가 작성 예정-








4. Databinding


다음으로 Databinding을 따로 정리하고자 한다.

기존에 프로젝트를 만들 때는 ViewBinding만 사용하였는데, Databinding은 가히 MVVM 패턴의 꽃이라고 볼 수 있다는 말을 듣고, MVVM 패턴을 완전히 이해하기 위해 Databinding에 대해 공부한 내용도 추가하고자 한다.


Databinding에 대해 알기 전까진 솔직히 ViewBinding에 비해 사용법이 불편하고, 불필요하다고 느꼈다.

dependency에 추가만 하면 쉽게 사용할 수 있는 ViewBinding과 다르게
XML 코드를 layout으로 감싸고 내부에 data class를 연결하는 일련의 과정이 있으니 말이다.

하지만 그것은 XML 파일에서 직접 view에 데이터를 할당하는 과정을 통해
View(Activity, Fragment)의 코드를 단순화할 수 있다는 이점을 알기 전까지였다.




코드를 직접보며 이해해보자.


  1. DataBinding을 사용하기 위해선, 앱 수준의 build.gradle 파일에 다음과 같이 DataBinding을 추가해주어야 한다.
dataBinindg {
	enabled = true
}



dependency에 추가만 하면 쉽게 사용할 수 있는 ViewBinding과 다르게
XML 코드를 layout으로 감싸고 내부에 data class를 연결하는 일련의 과정이 있으니 말이다.

하지만 그것은 XML 파일에서 직접 view에 데이터를 할당하는 과정을 통해
View(Activity, Fragment)의 코드를 단순화할 수 있다는 이점을 알기 전까지였다.




코드를 직접보며 이해해보자.


  1. DataBinding을 사용하기 위해선, 앱 수준의 build.gradle 파일에 다음과 같이 DataBinding을 추가해주어야 한다.
dataBinindg {
    enabled = true
}



  1. 다음은 DataBinding을 통해 적용될 데이터의 형식을 정의하기 위해 Data Class를 만든다.
data class Person(
    val name : String,
    val age : Int
)



  1. 다음은 DataBinding을 사용할 XML에 대한 설정이다.
<?xml version="1.0" encoding="utf-8"?>
<layout 
	xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="mainActivity"
            type="com.example.databindingpractice.Person" />
    </data>


<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/name_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{mainActivity.name}"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/age_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{Integer.toString(mainActivity.age)}"
        app:layout_constraintVertical_bias="0.6"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Databinding을 사용할 땐 일반적인 XML 코드와 차이가 있는데,

   1) 최상위 Layout을 layout을 통해 감싸고,

   2) type 부분에 정의해둔 Data Class의 주소값을 입력한다.

   3) 예시로 든 textview를 수정하려면, mainActivity(data의 name),
      name(data class의 변수)를 코드와 같이 @{} 안에 정의해주면 된다.




  1. 마지막으로 DataBinding을 사용할 Activity, Fragment을 다음과 같이 XML 파일과 연결한다.
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    }
}



5. DataBinding의 실 사용 예

정의했던 Data Class의 변수(name, age)에 어떤 내용을 넣을지 Activity나 Fragment에서 설정해야한다.


class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        
        val person = Person("홍길동", 17)

        binding.mainActivity = person
        
    }
}

여기까지만 봐도 DataBinding의 이점이 바로 드러난다.

만약 ViewBinding을 통해 위와 같이 데이터를 세팅해주었다면

binding.nameText.text = "홍길동"
binding.ageText.text = "17"

와 같이 각 view에 대한 데이터를 일일이 Activity에서 설정해주어야 하지만,

Databinding은 binding.mainActivity = person 한 줄로 처리가 가능하기 때문이다.
(데이터를 할당할 view가 많을수록 간편하다고 느껴질 것이다.)



-주의할 점-

지금은 예시이므로 각 변수에 직접 데이터를 넣어주고 있지만, 실제 사용 시에는 네트워크 통신을 위해 설정한 data class를 활용하면 DataBinding의 이점을 확실히 느낄 수 있을 것이다



-추가 작성 예정-



-고찰-

현재 진행중인 개인 프로젝트는 viewModel, LiveData만 사용하고,
Databinding을 적용하지 않아 UI 업데이트 및 View의 코드 단순화를 
충분히 활용하고 있지않은 상태이다.
추후 Databinding을 적용하는 방면으로 리팩토링 해보아야겠다.
profile
꾸준하게 배우자

0개의 댓글