MVVM 패턴의 적용에 대해서 적어보겠다.
먼저 액티비티에 대한 뷰모델 클래스를, ViewModel()을 상속받아서 만든다.
그리고 임의의 위젯의 값을 들고 있을 뮤터블라이브데이터를 만들고, (이건 내부적으로 사용할 변수로, _를 붙인 private이다) 이에 대한 게터와 세터도 만든다.
(세터는 반드시 만들 필요는 없는 것 같다. 추후에 더 알아보고 수정 예정)
class MainViewModel : ViewModel() {
private val _text1 = MutableLiveData<String>()
val text1: LiveData<String> get() = _text1
fun setText1(text: String) {
_text1.value = text
}
}
액티비티에 뷰모델 변수를 만들고 뷰모델 초기화 함수를 작성한다.
초기화 함수에서는 라이브데이터(게터)에 대한 옵저버를 만들어, 라이브데이터에 따라 위젯의 값을 변경하도록 한다.
// 액티비티에
private lateinit var viewModel: MainViewModel
// onCreate에
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
initViewModel(viewModel)
// 액티비티에
private fun initViewModel(vm: MainViewModel) {
vm.text1.observe(this) { binding.tv1.text = it }
}
이제 tv1에 표시되는 값을 변경해야 한다면 이에 대응되는 뷰모델의 text1 변수의 값을 바꿔주면 된다. text1의 값이 변경되면 지켜보고 있던 옵저버가 tv1에 반영한다.
// onCreate에
binding.btn1.setOnClickListener { viewModel.setText1("hi ${++cnt}") }
위에서는 비즈니스 로직이 딱히 없어서 액티비티에서 직접 값을 변경하고 있지만, 올바른 입력값인지 검증하여 에러 메세지를 텍뷰에 출력한다고 하면, 액티비티의 버튼 온클릭 함수에서는 viewModel.checkValidName(etName.text.toString()) 이렇게 되겠고, 뷰모델의 해당 함수에서 유효성 검증을 한 뒤에 텍뷰에 대응되는 변수를 변경해 에러메세지를 넣을 것이다. 그러면 해당 변수에 대한 옵저버가 변수가 변경되었다는 소식을 듣고 텍뷰에 반영하는 것이다.
이렇게 하면 기본적인 MVVM 패턴을 적용한 것이다.
이제 비즈니스 로직에 대한 것은 모두 뷰모델 클래스에서 처리하고, 액티비티에서는 뷰에 대한 것만 처리하면 된다.
=====
남은 의문점
굳이 겟셋 나눠야 하나? 그냥 뮤터블 변수 그대로 사용하면 안되나?
그리고, 라이브 데이터 변수명은 위젯에 맞춰서 tv1Text 식으로 맞춰줘야 헷갈리지 않을 것 같기도.