[Android] DataBinding의 동작방식 - 1. Setter Method와의 연결

아직 광범위하게 쓰이고 있는 것은 아니지만, 2015년도에 구글이 발표한 DataBinding이라는 개념이 있다.
이 DataBinding의 기본 사용법은 Developer Page에 워낙 자세하게 (심지어 한글) 정리되어있기 때문에, 굳이 별도로 사용법을 정리할 필요는 없다. 다만, Developer Page에 나와있지 않은 내용들도 꽤 있기 때문에 그에 관해서 몇화에 나눠서 정리해보려고 한다.
(아래 내용들은 Developer Page의 내용들을 어느정도 숙지 되었다는 전제로 진행됩니다.)

Developer Page Link : https://developer.android.com/topic/libraries/data-binding/index.html


"[Android] DataBinding의 동작방식" 전체목록
   1. Setter Method와의 연결
   2. BindingAdapter의 기본 및 사용 시점
   3. BindingAdapter의 사용시 팁
   4. include Tag 혹은 ViewStub 사용시의 Binding
   5. Listener, Callback
   6. InverseBinding (InverseBindingAdapter) + Two way Binding

  1. DataBinding의 기본
    : 어느정도 경력이 있는 개발자들은 조금 쓰다보면 알 수 있지만, DataBinding에서 중요한 것은, BuildTime에 Binding 코드가 생성된다는 것이다. 여기서 Binding Code라는 것은, "View와 Model을 연결해주는 작업을 대신 해주는 코드" 정도로 이해하면 된다.

     예를들어 activity_test.xml이라는 layout파일에 대응되는 Binding Code는 ActivityTestBinding.java라는 파일로 나타난다. 그리고 이 Class File 내에서는 View와 Model간의 관계를 XML상에 정의한 대로 Mapping 시켜주는 코드가 생성되어 있다. 이를 통해 개발자들은 View와 Model의 연결에 대한 코드 작성을 많이 줄일 수 있다.


  2. Setter Method와의 연결
    : 우선은 아래 코드를 보자.
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <data>
            <variable
                name="user"
                type="com.example.User" />
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:selected="@{user.isMan}" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.lastName}" />
    
        </LinearLayout>
    </layout>
    

    코드에서 보면 android:selected="@{user.isMan}" 부분이 있다. 의미로 보면 Man일때 해당 TextView를 Selected 상태로 바꾸라는 것인데, 직접 해보면 알겠지만, TextView는 xml상에서 Selected 를 설정할 수 있는 Attribute가 없다. 즉, DataBinding이 아니라면, android:selected에서 빌드에러가 떨어져야 정상이다. 그렇다면 이 XML을 빌드했을때 생성되는 Binding Code는 어떻게 생성되는지 확인해보자.

    if ((dirtyFlags & 0x3L) != 0) {
        // api target 1
        this.mboundView1.setSelected(userIsMan);
        android.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView2, userLastName);
    }
    

    위 코드를 보면 TextView의 setSelected() Method를 직접 호출해주고 그 안에 xml상에서 정의한 값을 넣어주는 것을 확인할 수 있다.

    DataBinding의 이러한 Code 생성방식을 이해한다면 다양한 부분에서 활용할 수 있다.

    하나의 예시를 들어본다면 아래와 같이 해볼 수 있다.
    아래는 ViewPager의 OffscreenPageLimit를 설정해 주는 부분인데, 보통은 ViewPager의 setOffscreenPageLimit()를 직접 호출해주어야 했다.
    하지만 위에서 살펴봤던 DataBinding을 통한 Setter Method와의 연결이라는 포인트를 이용한다면 아래와 같이 코드를 작성할 수 있다.
    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:offscreenPageLimit="@{3}"/>
    

    굳이 Java Code 내에서 해주는 것이 아니라, 이렇게 DataBinding을 이용해서 값을 설정해줄 수 있다. 한번 Binding Code쪽을 살펴보면 아래와 같다.
    if ((dirtyFlags & 0x2L) != 0) {
        // api target 1
        this.viewPager.setOffscreenPageLimit(3);
    }
    

    정확하게 Set Method를 찾아주는 것을 볼 수 있는데, 이러한 방법으로도 DataBinding을 활용할 수 있다. 이 예제에서 알 수 있는 것은, 굳이 Model의 어떤 값이 아니라, XML상에서 특정 상수를 입력하고 싶을때에도 DataBinding을 활용할 수 있다는 점이다. 

    ※ 주의 
    물론 이런식으로 사용할 때는 주의할 점이 있다.
    해당 View에 Setter Method가 존재해야 하고, 그것이 public이어야 한다는 것이다. 그리고 Setter Method의 Parameter가 1개여야한다는 것이다.

    이런식의 사용법을 쓰다보면 욕심이 생겨서 경험하게 되는 부분중의 하나가 바로 LayoutParam이다.
    LayoutParam은 xml상에서 android:layout_width, android:layout_height와 같은 방식으로 표현된다. 그런데 위와같이 바로 값을 Setting하고자 하는 마음에
    android:layout_width="@{viewModel.itemWidth}"과 같은 식으로 코드를 작성하게 되면 어떨까?
    당연히 에러를 밷어내고 빌드가 되지 않는다.

    왜일까?
    DataBinding을 통해 Binding Code가 생성되는 것은 내부적으로 2단계를 거쳐서 Method를 찾는다고 생각하면 이해가 쉽다.

    1단계 : @BindingAdapter로 정의된 모든 Method들에 매칭시켜본다. 만약 여기서 매칭이 되면 해당 Method를 Call하면서 적절하게 Parameter를 넣어주게 된다. 만약 Parameter 갯수가 맞지 않거나 Type이 맞지 않는다면 생성된 Binding Code에서 빨간줄이 그어지게 된다.

    2단계 : 만약 @BindingAdapter에서 찾지 못했다면, Setter Method를 찾아본다. 이 때 @BindingMethod Annotation까지 참고해서 적절한 Set Method를 찾아보게 되는데, 기본적으로는 XML에서 넣어준 Attribute의 이름에서 Namespace를 제외하고 남은 String에서 앞에 set을 붙여보는 수준이다.
    위의 예시를 다시 가져와보면 android:selected="@{true}"라고 했을 때, android:selected에서 Namespace인 android를 제외한 selected에서 앞에 set을 붙인 setSelected를 찾아보게 되는 것이다. 만약 존재한다면 해당 Method를 Call해준다.


    만약 이 2단계 내에서 걸리지 않은 XML상의 속성들이 존재한다면 빌드에러를 발생시키게 된다. 당연 Binding Code도 생성되지 않는다.
일단 이번 포스트에서는 DataBinding에서 Setter Method와 연결되는 부분에 대해서 알아봤다.
다음 포스트에서는 BindingAdapter와 include / ViewStub의 처리에 대해서 DataBinding이 어떻게 처리되는지 알아보도록 한다. (+ 관련 팁들도!)

댓글

  1. 글을 보며, view 에 특정 상태를 주기위해 customWidget이나, code로 하던 작업들을 대체할수 있는 기능으로도 좋겠네요!! 좋은글 감사합니다.

    답글삭제

댓글 쓰기

이 블로그의 인기 게시물

[Android] DataBinding의 동작방식 - 4. include Tag 혹은 ViewStub 사용시의 Binding

[Android] DataBinding의 동작방식 - 5. Listener, Callback (CustomView의 Callback을 람다식으로 Binding하기)

[Android] DataBinding의 동작방식 - 2. BindingAdapter의 기본 및 사용 시점