[Android, Kotlin] AAC – DataBinding 예제
Android Jetpack 은 개발자가 고품질 앱을 쉽게 개발할 수 있도록 지원하는 라이브러리, 도구, 가이드의 모음 입니다. Jetpack 은 androidx.* 패키지 라이브러리로 지원되며, 크게 4가지 구성요소(기초, 아키텍처, 동작, UI)를 가집니다.
이번 포스트에서 다룰 주제는 아키텍처 구성요소 중 Data Binding 입니다.
DataBinding 을 사용함으로써 View(xml 파일) 은 코틀린 코드와 아래와 같은 방법으로 직접 연결될 수 있습니다.
- Variable 참조
- View(xml 파일) 에서 코틀린 코드의 데이터를 직접 참조할 수 있습니다.
- 2-way data binding
- View 에서 변경된 데이터를 코틀린 코드가 참조할 수 있도록 설정할 수 있습니다. (EditText 의 입력값 등… 이번 예제에서는 이 케이스는 빠져있습니다.)
- Listener 바인딩
- 버튼 Click 과 같은 event 를 처리할 리스너를 View 에서 지정할 수 있습니다.
- 표현식 삽입
- 함수 호출이나 3항 연산자 같은 간단한 코드를 View에 넣을 수 있습니다. 아래 layout 예제를 보시면 사용법을 이해하실 수 있을겁니다.
- https://github.com/android/databinding-samples/blob/master/BasicSample/app/src/main/res/layout/observable_field_profile.xml
위와 같은 DataBinding 방법에 따라 따라서 Activity가 비대해지거나 boilerplate 코드가 늘어나는 것을 막고, MVVM 패턴을 효율적으로 구현할 수 있는 도구가 될 수 있습니다.
.
.
DataBinding 예제
DataBinding 구현 예제는 GitHub – DataBindingExample 에서 보실 수 있습니다.
이번 예제에서는 앞서 LiveData 에서 사용했던 예제와 같은 기능을 구현합니다. 아래처럼 버튼을 클릭하면 클릭 횟수를 1씩 증가해서 출력하도록 되어 있습니다.
또한 ViewModel / LiveData 예제에서 사용했던 예제를 기반했기 때문에 ViewModel – LiveData – DataBinding 이 함께 동작하도록 구현했습니다. LiveData 예제와 코드를 비교해보시면 더욱 이해가 편할 것입니다.
- LiveData 예제 : http://roasterhouse.com/?p=12341
.
LiveData 및 DataBinding 사용을 위해 app 모듈의 gradle 파일에 아래 내용 추가가 필요합니다.
apply plugin: 'kotlin-kapt' android { ...... dataBinding { enabled = true } }
소스를 보면 2개의 코틀린 파일이 있습니다.
- MainActivity.kt
- Activity 에서 사용할 view(xml)를 binding
- Lifecycle owner 설정
- ViewModel 생성 및 초기화
- Binding 객체와 view model 연결
class MainActivity : AppCompatActivity() { private lateinit var viewModel : MainViewModel private lateinit var binding : ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // setContentView(R.layout.activity_main) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding.apply { lifecycleOwner = this@MainActivity } // create basic view model viewModel = ViewModelProvider(this).get(MainViewModel::class.java) // initialize view model viewModel.init() // set view model to binding object binding.vm = viewModel } }
MainViewModel.kt
- MutableLiveData 생성
- init() 초기화 함수
- clickButton() 클릭 이벤트 처리 함수
- ViewModel – onCleared() 구현
class MainViewModel : ViewModel() { val TAG = "MainViewModel" private var count = 0 val countText : MutableLiveData<String> = MutableLiveData() fun init() { countText.value = "click count : $count" } fun clickButton() { countText.value = "click count : ${++count}" } override fun onCleared() { Log.d(TAG, "## MainViewModel - onCleared() called!!") Log.d(TAG, "## count = $count") super.onCleared() } }
DataBinding 을 사용하기 위해서는 layout 파일에도 적절한 처리를 해야 합니다.
activity_main.xml
<layout> <data> <import type="android.view.View" /> <variable name="vm" type="com.example.databindingexample.MainViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout 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" 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" android:gravity="center_horizontal"> <TextView android:id="@+id/text_desc1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{vm.countText}" android:textSize="20sp"/> <Button android:id="@+id/button_class" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Increase count" android:onClick="@{(view) -> vm.clickButton()}"/> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
XML 레이아웃 파일에서 DataBinding 을 사용하기 위해서는 레이아웃 전체를 태그로 감싸야합니다. 그리고 layout 태그 바로 아래에 data 태그를 이용해서 XML 에서 참조할 클래스(여기서는 MainViewModel)를 선언해줘야 합니다.
<data> <import type="android.view.View" /> <variable name="vm" type="com.example.databindingexample.MainViewModel" /> </data>
클릭 횟수 문자열을 출력할 TextView 는 ViewModel 에 선언해놓은 LiveData 변수를 참조하도록 설정합니다. 이렇게 함으로써 LiveData 형 countText 변수의 값이 변경되면 자동으로 TextView 문자열이 변경됩니다.
@{vm.counText}
<TextView android:id="@+id/text_desc1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{vm.countText}" android:textSize="20sp"/>
추가로 버튼이 클릭되면 ViewModel 의 clickButton() 함수가 호출되도록 리스너를 설정했습니다. 람다 표현식 형태로 호출할 수 있습니다.
@{(view) -> vm.clickButton()}
<Button android:id="@+id/button_class" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Increase count" android:onClick="@{(view) -> vm.clickButton()}"/>
이제 버튼을 누르면 ViewModel 의 clickButton() 이 호출되면서 LiveData 로 선언된 countText 문자열을 변경합니다. 그러면 다시 LiveData를 참조하는 TextView 의 문자열이 함께 변경됩니다.
.
View 에서의 처리는 모두 끝났으므로 이제 Activity 에서 View 와 ViewModel, DataBinding 이 상호 연결되도록 설정해주면 됩니다.
Activity 에서는 먼저 기존에 사용하던 setContentView() 대신 DataBindingUtil 을 이용해서 레이아웃을 inflate 합니다. 이때 DataBinding 객체의 lifecycleOwner 를 설정해줘야 합니다. 그렇지 않으면 LiveData 에서 lifecycleOwner를 참조할 수 없어 View 에서 LiveData 의 값을 참조하지 못합니다. (만약 LiveData 를 사용하지 않는다면 binding.apply{} 를 생략)
import com.example.databindingexample.databinding.ActivityMainBinding private lateinit var binding : ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // setContentView(R.layout.activity_main) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding.apply { lifecycleOwner = this@MainActivity }
DataBinding 객체가 ActivityMainBinding 으로 선언되어 있음을 주의할 필요가 있습니다. ActivityMainBinding 클래스는 레이아웃의 명칭 activity_main.xml 에서 카멜 케이스로 변경한 뒤, Binding 을 붙여 자동 생성됩니다.
.
DataBindingUtil 을 이용한 layout inflate 작업과 DataBinding 객체 생성이 끝나면 ViewModel 초기화 후 ViewModel – DataBinding 연결을 해주면 됩니다.
// create basic view model viewModel = ViewModelProvider(this).get(MainViewModel::class.java) // initialize view model viewModel.init() // set view model to binding object binding.vm = viewModel
이후부터는 activity 를 거치지 않고 View 와 ViewModel 이 상호작용을 할 수 있습니다.
DataBinding 활용
DataBinding을 활용하면 View(xml 파일)가 원하는 코드에 바로 연결될 수 있으므로 Activity 에서 View를 처리하기 위해 생성했던 boilerplate 코드와 로직을 상당히 줄여줄 수 있습니다.
특히 MVVM 패턴 구현에 활용하면 View – View model 간의 의존성을 낮춰줄 수 있으므로 보다 효율적인 앱 구조를 구현할 수 있습니다.
.
참고
- DataBinding : https://medium.com/@PaperEd/android-how-to-databinding-169c78e7dc28
- https://superwony.tistory.com/42
- https://gamjatwigim.tistory.com/88
- 아키텍처 구성요소에 레이아웃 뷰 결합 : https://developer.android.com/topic/libraries/data-binding/architecture?hl=ko
- View 에서의 data binding 표현식 예제 : https://github.com/android/databinding-samples/blob/master/BasicSample/app/src/main/res/layout/observable_field_profile.xml
- https://woovictory.github.io/2019/02/04/Android-What-is-DataBinding-1/
.
.