DataBinding
은 JetPack 아키텍처에 포함된 라이브러리이다.
DataBinding
을 사용하면 선언적 형식으로 레이아웃의 UI구성 요소를 앱의 데이터와 결합할 수 있다.
대표적인 장점으로는 findViewById
메소드를 호출할 필요가 없어 보일러플레이트 코드를 방지할 수 있고, 앱 성능이 향상되며, 메모리 누수 및 NullPointerException
을 방지할 수 있다.
간단한 샘플 앱 구현을 통해 DataBinding
을 살펴보자.
샘플 앱은 Add 버튼을 누르면 Count 값이 올라가 텍스트뷰에 실시간으로 표시되고, Reset 버튼을 누르면 Count 값이 초기화되는 예제이다.
DataBinding 설정하기
DataBinding
은 Android Studio 버전은 1.5.0 이상이어야 하고,
Android 4.0(API 14 Level) 이상 안드로이드 기기에서 지원한다.
plugins {
...
id 'kotlin-kapt'
}
android {
...
dataBinding {
enabled = true
}
}
...
☝️ Kotlin을 사용하는 경우 kotlin-kapt
플러그인을 추가해야 한다.
Binding class 생성하기
레이아웃의 변수와 뷰를 참조할 수 있는 Binding class를 생성해야 한다.
생성하는 방법은, XML 레이아웃 파일에서 가장 상위 레이아웃을 <layout>
태그로 감싸면 클래스가 자동으로 생성된다.
생성되는 클래스 이름은 XML 레아아웃의 파일명을 파스칼 케이스로 변경한 뒤 접미어 Binding을 붙인다.
ex) activity_main.xml
을 표현하는 Binding class 이름은 ActivityMainBinding
이다.
<?xml version="1.0" encoding="utf-8"?>
<layout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
</LinearLayout>
</layout>
Binding class로 Binding 객체 생성하기
바인딩 객체를 생성하자.
여러 방법이 있는데, 그 중 DataBindingUtil
클래스를 활용하면 setContentView
메소드를 대체할 수 있다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
}
}
☝️ 아까전에 <layout>
으로 XML 레이아웃 파일을 감쌌기 때문에, 자동으로 ActivityMainBinding
이라는 Binding class가 생성되어 있다.
ViewModel 생성하기
버튼을 누르면 카운트 값이 갱신되고 리셋되는 기능을 구현해보자.
class MyViewModel {
private var count: Int = 0
private val txtCount = ObservableField<String>()
init {
updateTxtCount()
}
fun getTxtCount() : ObservableField<String> = txtCount
private fun updateTxtCount() {
txtCount.set("$count clicked!!")
}
// Reset 버튼을 눌렀을 때 동작한다.
fun resetCount() {
count = 0
updateTxtCount()
}
// Add 버튼을 눌렀을 때 동작한다.
fun addCount() {
++count
updateTxtCount()
}
}
여기서 짚고 넘어가야할 점은 텍스트뷰에 찍을 데이터를 ObservableField<String>
으로 선언했다는 것이다.
Observable
데이터 객체는 데이터의 변경 사항을 감지하고 알려주는 객체이다.
데이터 바인딩 라이브러리에는 Observable
을 구현한 여러가지 클래스들을 제공하므로 직접 구현할 필요는 없을 것이다.
ViewModel binding
이제 생성한 ViewModel
을 Binding class에 binding(?) 해야한다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
binding.viewmodel = MyViewModel()
}
}
XML 레이아웃에서 변수 선언하기
XML 레이아웃에 변수를 선언하고, 이 변수에 값을 대입하는 것으로 뷰 상태를 변경할 수 있다.
우리는 앞서 생성한 ViewModel
의 필드를 사용할 것이기 때문에, ViewModel
변수를 선언한다.
<layout ...>
<data>
<variable
name="viewmodel"
type="com.example.databindingsample.viewmodel.MyViewModel" />
</data>
...
</layout>
이벤트 처리하기
이제 각 View widget의 이벤트를 처리한다.
다음은 activity_main.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.example.databindingsample.viewmodel.MyViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/txt_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@{viewmodel.txtCount}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/bt_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="버튼"
android:onClick="@{() -> viewmodel.addCount()}"
app:layout_constraintTop_toBottomOf="@+id/txt_count"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/bt_reset"/>
<Button
android:id="@+id/bt_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="리셋"
android:onClick="@{() -> viewmodel.resetCount()}"
app:layout_constraintTop_toBottomOf="@+id/txt_count"
app:layout_constraintStart_toEndOf="@+id/bt_add"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
☝️ android:onClick
에서 버튼 이벤트를 실행하는 방법을 리스너 바인딩이라고 한다.
이벤트를 다루는 방법에는 메소드 참조와 리스너 바인딩 두 가지 방법이 있다.
결과