Data Binding Guide-4

SeungyongYun
7 min readApr 25, 2016

--

이 문서는 구글의 Data Binding Guide의 내용을 번역후, 일부 수정하여 작성되었습니다.

이번에는 지난 시간에 이어 layout 파일에 실질적으로 Obejct를 바인딩 시키는 방법과 그로 인해 생성되는 파일들에 대해서 알아보겠습니다.

Generated Binding

Generated Binding클래서는 같은 레이아웃 내의 레이아웃 변수와 뷰를 연결시켜줍니다. 보통 자동으로 이름과 패키지를 지정해주지만, 이는 원할 경우 커스터마이징이 가능합니다. 이 Generated Binding 클래스들은 모두 ViewDataBinding 클래스를 상속 받습니다.

Creating

레이아웃 내에서 뷰 계층이 binding되기 전에 보여지지 않도록, binding은 뷰가 생성되고 최대한 빨리 이루어져야 합니다.. 그래서 이를 보장하기 위해서 layout에 바인딩시키기 위한 몇가지 방법이 있는데 가장 흔한 방식은 Binding클래스의 static메서드를 사용하는 것입니다. static 메서드를 사용해서 뷰 계층을 생성하면 뷰 계층과 바인딩이 한번에 처리가 됩니다.

MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);

만약 레이아웃이 다른 방식으로 Inflate되야 한다면, 다음과 같은 방식으로 분리해서 바인딩 시켜주면 됩니다.

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);

간혹 언제 바인딩되야하는지 모를 때, DataBindingUtil 클래스를 사용하면 됩니다.

ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId,
parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);

Views with IDs

이렇게 바인딩을 할 경우에, 해당하는 바인딩클래스 내에 xml파일 내에서 각 뷰에 지정된 ID를 기반으로 public final field View가 생성되게 됩니다. 이 기법은 몇몇 뷰에서는 findViewById 보다 더 빠를 수가 있습니다.

<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:id="@+id/firstName"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"
android:id="@+id/lastName"/>
</LinearLayout>
</layout>

item_single_selection.xml이 다음과 같이 작성되어있다면, 이를 통해 생성된 ItemSingleSelectionBinding 클래스 내에 다음과 같은 필드를 생성합니다.

public final TextView firstName;
public final TextView lastName;

Variables

<data> 태그 내에 지정된 변수는 자동으로 Getter/Setter가 생성됩니다.

<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
public abstract com.example.User getUser();
public abstract void setUser(com.example.User user);
public abstract Drawable getImage();
public abstract void setImage(Drawable image);
public abstract String getNote();
public abstract void setNote(String note);

ViewStubs

저 같은 경우에는 거의 사용하지 않지만, ViewStub은 일반 뷰와는 조금 다릅니다. 애초에 보이지 않던 뷰가 필요할 때에 다른 레이아웃으로 Inflate되는 형태이기 때문에, 뷰 계층에서 보이지 않아야 합니다. 하지만 뷰들은 위에서 본 것 처럼 final이기에, ViewStub 대신 ViewStubProxy라는 객체를 생성하게 됩니다. 이 객체를 통해서 개발자는 해당 ViewStub이 존재할 때 접근 할 수 있을 뿐더러, ViewStub이 inflate될 때, 뷰 계층을 inflate하기 위해 접근 할 수도 있습니다.

ViewStub을 inflate할 때는 반드시, 새 레이아웃에 바인딩 작업을 해줘야 하므로, ViewStubProxy는 반드시 ViewStub.OnInflateListener를 통해 inflate타이밍에 바인딩을 해줘야합니다.

Advanced Binding

Dynamic Variables

RecyclerView.Adapter 처럼, 한 종류의 뷰 뿐만 아니라 여러 종류의 뷰를 가지고 있을 수 있는 환경에서 특정한 바인딩클래스로 한정 시킬 수 없게 됩니다. 이럴땐 반드시 onBindViewHolder(VH, int) 함수 내에서 각 변수들을 동적으로 바인딩해주어야 합니다.

public void onBindViewHolder(BindingHolder holder, int position) {
final T item = mItems.get(position);
holder.getBinding().setVariable(BR.item, item);
holder.getBinding().executePendingBindings();
}

Immediate Binding

변수나 Observable이 변경되었을 때, 바인딩은 다음 프레임에 변경되도록 스케쥴을 정합니다. 하지만 즉시 반영되어야 한다면 executePendingBindings()메서드를 통해 강제로 바인딩 시킬 수 있다. 위의 예시 처럼.

Background Thread

원한다면, 콜렉션이 아닌 한 데이터 모델을 백그라운드 쓰레드에서 변경할 수 있습니다. Data binding이 동시성 문제를 피하기 위해, 변수나 필드를 계산하는 중에는 바로 반영하지 않기 때문입니다.

--

--