본문 바로가기
Android

[Android] MVVM 패턴 (feat. DataBinding)

by Ejay 2022. 12. 12.

MVVM ?

MVVM패턴은 Model, View, ViewModel을 분리하여 뷰와 모델간의 의존성을 줄여주는 패턴이다.

 

Activity, Fragment와 Repository가 분리되어 있고, 이 분리된 두 로직 사이에서 뷰의 이벤트에 따라 모델이 데이터를 반환, 저장 하도록 통신하는 뷰모델이 존재한다.

 

뷰에서 이벤트를 발생시켜 데이터를 요청하게 되면 뷰모델에서 해당 데이터를 호출하는 메소드를 호출하고 모델에서 뷰모델에서 요청하는 값을 반환하고 뷰모델은 모델로부터 받은 값을 라이브데이터에 저장하고 뷰에서는 라이브데이터를 감지하여 뷰에 출력하는 형식이다.

 

MVVM 선택이유

안드로이드에서 주로 사용하는 패턴은 MVC(Model, View, Controller), MVP(Model, View, Presenter), MVVM가 있다.

 

MVC의 경우 View와 Controller가 Activity안에서 모두 처리돼야하기 떄문에 Activity가 너무 커지고 원하는 메소드를 찾기가 버거우며 유지보수에 불리하다고 생각하였다.

MVP는 Presenter가 뷰와 1 : 1 로 동작하기 떄문에 뷰와 프레젠터의 의존성이 강해지고 이에따라 프레젠터의 로직이 커지는 문제가 있기도 하였다.

따라서 뷰와 모델의 관심사를 분리시키고 화면회전등에도 뷰모델을 통해 데이터를 유지할 수 있는 MVVM을 선택하기로 하였다.

 

MVVM 적용방법

 

간단히 버튼을 눌렀을 때 데이터를 호출하여 뷰에 출력하는 예제를 작성해보겠다.

 

DataBinding 사용을 위해 build.gradle에 아래의 코드를 추가한다.

 

android {
...
dataBinding {
        enabled = true
    }
}

 

activity xml 파일에 아래와 같이 추가한다.

 

<layout>
    <data>
        <variable
            name="inputs"
            type="com.example.mvvmtest.MainInputs" />

        <variable
            name="vm"
            type="com.example.mvvmtest.MainViewModel" />
    </data>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <Button
            android:id="@+id/btn_get_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="데이터 호출"
            android:textColor="@color/white"
            android:onClick="@{() -> inputs.onDataButtonClick()}"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/tv_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="@{vm.data.toString()}"
            android:textColor="@color/black"
            android:textSize="16sp" />

    </LinearLayout>
</layout>

databinding을 사용하기위해 xml을 layout으로 덮어주어야 하며 위의 코드를 적용하면 아래와 같이 뷰가 배치된다.

 

View와 Viewmodel은 아래와같이 하였다.

class MainActivity : AppCompatActivity() {
    lateinit var binding: ActivityMainBinding
    lateinit var viewModel: MainViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
        binding.inputs = viewModel.inputs
        binding.vm = viewModel
        binding.lifecycleOwner = this
    }
}
...
class MainViewModel() : ViewModel(), MainInputs {
    private val mainRepository = MainRepository()
    val inputs: MainInputs = this

    private val _data = MutableLiveData<String>("데이터 대기")
    val data: LiveData<String> = _data


    override fun onDataButtonClick() {
        _data.value = mainRepository.getData()
    }

}
...
class MainRepository {
    private val data = "Data 호출 성공"

    fun getData() = data
}

interface MainInputs {
    fun onDataButtonClick()
}

에뮬레이터가 말썽이라 글로 설명하자면 앱을 실행해보면 버튼을 눌렀을 떄 Repository에 있는 데이터가 정확히 들어오는 것을 확인할 수 있다. 반쪽짜리 databinding을 사용했지만 다음에 자세히 다루도록 하겠다.

반응형

'Android' 카테고리의 다른 글

ADB로 APK 설치하기  (0) 2024.12.01
[Android] BindingAdapter  (0) 2022.12.12
[Android] 사용 중인 플러그인  (0) 2022.12.06
[Android] 디자인 패턴  (0) 2022.07.27