최근 MVVM 관련 학습을 하던 중 LiveData와 Databinding을 함께 사용하는 경우가 많았다. LiveData가 사용하는 것이 오늘 정리해 볼 관찰자 패턴이다.
Observer Pattern? 관찰자 패턴?
단어 그대로, 무엇인가를 살펴보는 것을 의미한다.
관찰자 패턴은 객체의 상태 변화를 관찰하는 관찰자(옵저버)의 목록을 객체에 등록해서 상태변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 알리도록 하는 디자인 패턴이다.
이 패턴의 핵심은 옵저버 또는 리스너라 불리는 하나 이상의 객체를 관찰 대상이 되는 객체에 등록시킨다. 그리고 각각의 옵저버들은 관찰 대상인 객체가 발생시키는 이벤트를 받아 처리한다. 이벤트가 발생하면 각 옵저버는 콜백을 받는다.
데이터가 변화하는 것을 관찰해서 데이터가 변하면 해당하는 동작을 실행시키도록 하는 리액티브 프로그래밍 패러다임이 현재 중요한 패러다임 중 하나인데, Observer Pattern은 이러한 리액티브 프로그래밍의 기초가 되는 패턴이다.
실제로 ViewModel에서 LiveData의 값이 변경되면 해당 UI(Activity, Fragment)로 값이 변경되었다는 신호(?)를 보내게 된다.
그럼 UI에서 Observer Pattern을 활용하여 관찰 대상인 객체의 변화에 따라 해당하는 코드를 실행시킨다.
이런 식으로, MVVM 패턴에서 ViewModel에 LiveData를 활용하여 값의 상태를 전달하고, Activity에서 관찰하며 값의 변화가 있을 때 UI를 변경시켜 주는 것이다.
Example(DataBinding + ViewModel + LiveData)
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="viewModel"
type="com.pys.ex_livedata.MainViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:id="@+id/textV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(viewModel.testData)}"
android:textSize="50dp" />
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PLUS"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
private lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
binding.btn.setOnClickListener {
mainViewModel.plusLiveDataValue()
}
// observer pattern
mainViewModel.testData.observe(this, Observer{
Log.d("Checking Number : ", it.toString())
binding.textV.setText(it.toString())
})
}
}
MainViewModel
class MainViewModel : ViewModel() {
private var _testData = MutableLiveData(0)
val testData : LiveData<Int> get() = _testData
fun plusLiveDataValue() {
_testData.value = (_testData.value)?.plus(1)
}
}
LiveData를 초기화하기 위해, dependencies를 추가해줘야 한다.
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
위와 같이 코드를 작성하면, Plus 버튼을 누를 때마다 로그에도 값이 1씩 증가되고, 화면에 보이는 숫자도 증가한다.
정리하며
아마 실제로 앱 개발을 하게 되면 위처럼 간단하게 사용하진 않겠지만, 가볍게 개념을 익히기는 좋은 예제인 것 같아 따라 해 보고 정리해 보았습니다.
데이터 바인딩을 활용하면 사실, 위에 예제처럼 setText를 하지 않고 BindingAdapter를 활용하는 것도 좋은 방법입니다.
다음엔 BindingAdapter에 관해 공부해서 정리해 보도록 하겠습니다.
모두 즐코😄
Reference
LiveData 개요 | Android 개발자 | Android Developers
LiveData를 사용하여 수명 주기를 인식하는 방식으로 데이터를 처리합니다.
developer.android.com