Databinding
Databinding에 추가되어야 하는 글이지만 새로운 글로 이어서 쓴다. 이전 글에서 사용한 예제 프로젝트를 사용하여 변경하는 과정을 다룬다. 먼저 build.gradle에 id 'kotlin-kapt'를 추가하고 시작한다. 해당 플러그인을 적용하면 DataBinding에서 코틀린 애노테이션 처리할 수 있다.
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
[예제 코드 파일]
Databinding이 변경된 값을 View에 반영하는 과정은 사실 프레임워크에 값을 할당하는 과정을 거친다. 이러한 작업을 하는 것이 바로 BindingAdapter이다.
예를 들어 다음과 같이 android:text에 텍스트를 반영하려고 한다면 setText() 메서드를 찾아서 값을 할당한다. 좀 더 상세한 과정을 살펴보면 test.text의 값을 가져오기 위해 test.getText()라는 getter에서 가져온 리턴 타입에 맞는 setText(arg) 메서드를 찾는다. test.getText()의 리턴 타입이 String이면 setTest(String) 메서드를 찾는 식이다.
정리하자면 Databinding 라이브러리는 text라는 멤버 변수가 있다면 해당 데이터형에 맞는 파라미터를 가지는 setText(arg)를 자동으로 찾는다는 것이다. 만약 멤버 변수는 없지만 setter가 있는 경우는 해당 setter를 사용한다.
그러나 어떤 멤버 변수는 setter가 set변수명()의 형태로 되어 있지 않은 경우가 있다. 이런 경우 BindingMethods 애노테이션을 사용하여 setter와 연결할 수 있다.
예를 들어 android:tint의 경우 setTint()라는 메서드는 없고 setImageTintList(ColorStateList) 메서드가 있다. 이것은 다음과 같이 BindingMethods를 구성하여 연결할 수 있다.
이렇게 연결된 경우는 다음과 같이 레이아웃 파일에서 android:tint가 아닌 my:tint로 사용된다. my는 임의로 부여한 이름으로 사용자가 지정할 수 있다.
하지만 일반적인 경우 적절한 메서드를 자동으로 찾도록 구현되어 있기 때문에 변수명과 setter가 일치하지 않는다고 하여 매번 이렇게 지정해 줄 필요는 없다. 이런 것이 있구나 정도로 생각하면 되고 실제로 쓸 일은 거의 없다.
만약 특정 멤버 변수에 연결된 setter가 없다면 어떻게 해야 할까? BindingAdapter 애노테이션을 사용하여 직접 설정할 수 있다. ImageView에 Bitmap을 지정하는 경우를 생각해 보자. TextView의 Databinding처럼 생각하면 다음과 같이 지정하면 될 것 같다.
그러나 src에는 setImageResource(int resId) 메서드가 있지만 Bitmap을 파라미터로 넘겨주는 setter는 없다. 따라서 에러가 발생한다. (물론 setImageResource(int resId)가 내부적으로 setImageDrawable(Drawable) 메서드를 호출하기 때문에 Drawable 객체를 할당해 주면 이 문제는 해결할 수 있다. lateinit var bmp: Bitmap을 lateinit var bmp: Drawable로 바꾼 후 적절한 값을 할당하면 된다.)
이 경우에는 BindingAdapter 애노테이션으로 새로운 setter를 지정한다. 예를 들면 다음과 같이 setImageResource 메서드를 정의한다. 새로운 setter의 생성인 것이다. 이때 파라미터의 타입이 중요하다. 첫 번째 파라미터는 멤버 변수와 연결된 뷰의 타입을 지정하고 두 번째 파라미터는 멤버 변수의 타입을 지정한다. 그리고 실제로 Bitmap을 파라미터로 사용하는 setImageBitmap 메서드를 호출하여 멤버 변수를 적용한다.
BindingAdapter 애노테이션에서 지정한 value 값이 이제 레이아웃 파일에서 사용될 수 있는 속성이다. 따라서 다음과 같이 imgRes를 이용할 수 있다.
이때 커스텀한 뷰의 추가된 속성을 사용하기 위해 my는 다음과 같이 지정한다.
따라서 my:imgRes와 같은 방식으로 접근이 가능하게 되는 것이다.
코드는 기존 예제에서 다음과 같이 변경되었다.
ImageView에 Bitmap과 tint가 잘 적용되는 것을 확인할 수 있다.