이번 포스팅에서는 지금까지 했던 예제에 DataBinding을 적용해보겠습니다.
DataBinding이란, 간단하게 설명하자면 Layout의 UI 구성요소를 프로그래밍 방식(findViewById 등)이 아닌 선언적인 형태를 사용하는 것입니다. 즉, UI의 구성 요소 중 View에 데이터 소스를 Binding하는 작업을 DataBinding이라고 합니다.
이론 설명보다 직접 코드를 보며 어떤 차이가 있는지 확인하며 이해하도록 하겠습니다!
가장 먼저, build.gradle에 dependency를 추가합니다.
android {
buildFeatures {
dataBinding true
}
}
DataBinding의 XML 정의
기존 코드와는 달리 <layout>이라는 태그로 감싸며 각 View에 Binding시킬 Data를 <data>를 통해 선언합니다.
만약, import 작업이 필요한 경우, <import>를 사용할 수 있습니다.
<layout>
<!-- data 정의 -->
<data>
<variable name="obj" type="Item"/>
</data>
<!-- layout 정의 -->
<LinearLayout>
...
</LinearLayout>
</layout>
1. note_item
RecyclerView의 item layout인 note_item에 위와 같은 형태의 코드를 작성해줍니다. 각 TextView의 android:text 요소를 보면 "@{ ... }"를 확인할 수 있습니다. 이는 각 View에 적절한 데이터 소스를 설정해주는 작업입니다. 다만, 만약 객체의 컬럼 중 문자열이 아닌 경우, 반드시 String 형태로 미리 바꿔줘야 합니다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="note"
type="com.heon9u.aacproject.Note"/>
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="@+id/text_view_priority"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:text="@{String.valueOf(note.priority)}"
android:textAppearance="@style/TextAppearance.AppCompat.Large"/>
<TextView
android:id="@+id/text_view_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{note.title}"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:maxLines="1"
android:layout_toStartOf="@id/text_view_priority"
android:layout_alignParentStart="true"
android:ellipsize="end"/>
<TextView
android:id="@+id/text_view_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text_view_title"
android:text="@{note.description}"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
</layout>
2. NoteAdapter
이번에는 RecyclerView에 List 객체를 Binding해주는 Adapter코드를 수정합니다. (편의상 import문은 삭제했습니다.)
바뀐 메서드는 총 3개입니다. 먼저, NoteHolder Class에서 기존 TextView와 ItemView대신 NoteItemBinding을 활용합니다.
Binding Class의 이름은 이미 정해져있습니다. 만약, simple_layout.xml에서 DataBinding을 사용할 경우, Java 코드에서 SimpleLayoutBinding으로 생성됩니다.
두번째로 Holder가 변경됨에 따라 onCreateViewHolder와 onBindViewHolder의 코드를 수정합니다.
기존에는 onBindViewHolder에서 Holder에 데이터를 하나씩 set했습니다. 반면에, DataBinding은 한 줄로 코드를 요약할 수 있습니다.
import com.heon9u.aacproject.databinding.NoteItemBinding;
public class NoteAdapter extends ListAdapter<Note, NoteAdapter.NoteHolder> {
private OnItemClickListener listener;
public NoteAdapter() {
super(DIFF_CALLBACK);
}
private static final DiffUtil.ItemCallback<Note> DIFF_CALLBACK = new DiffUtil.ItemCallback<Note>() {
@Override
public boolean areItemsTheSame(@NonNull Note oldItem, @NonNull Note newItem) {
return oldItem.getId() == newItem.getId();
}
@Override
public boolean areContentsTheSame(@NonNull Note oldItem, @NonNull Note newItem) {
return oldItem.getTitle().equals(newItem.getTitle()) &&
oldItem.getDescription().equals(newItem.getDescription()) &&
oldItem.getPriority() == newItem.getPriority();
}
};
@NonNull
@Override
public NoteHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.note_item, parent, false);
NoteItemBinding itemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.note_item, parent, false);
return new NoteHolder(itemBinding);
}
@Override
public void onBindViewHolder(@NonNull NoteHolder holder, int position) {
Note currentNote = getItem(position);
holder.itemBinding.setNote(currentNote);
}
public Note getNoteAt(int position) {
return getItem(position);
}
class NoteHolder extends RecyclerView.ViewHolder {
private final NoteItemBinding itemBinding;
public NoteHolder(@NonNull NoteItemBinding itemBinding) {
super(itemBinding.getRoot());
this.itemBinding = itemBinding;
itemView.setOnClickListener(v -> {
int position = getAdapterPosition();
if (listener != null && position != RecyclerView.NO_POSITION) {
listener.onItemClick(getItem(position));
}
});
}
}
public interface OnItemClickListener {
void onItemClick(Note note);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
}
여기까지 DataBinding을 이용한 작업을 마쳤습니다. Java코드를 요약한다는 장점은 있지만, XML코드가 늘어난다는 단점이 있습니다. 보통 XML보다 Java 코드의 양이 많기 때문에 스케일이 큰 어플리케이션의 경우, DataBinding의 효율이 높아진다고 생각합니다.
특히, DataBinding과 LiveData 함께 활용한다면, 장점은 배가 됩니다.
- findViewById()를 쓰지않아도 View에 적절한 데이터를 설정할 수 있다.
- Data가 실시간으로 변경될 때, Observer를 활용하면 View도 함께 변경된다.
- ListView나 RecyclerView를 활용할 때, 각 item을 세팅해주는 작업을 DataBinding으로 짧게 구현할 수 있다.
'Android > study_til' 카테고리의 다른 글
[AAC] ViewModel을 써야하는 이유? (0) | 2021.07.06 |
---|---|
[AAC] LiveData를 써야하는 이유? (0) | 2021.07.06 |
[AOS] Room + ViewModel + LiveData + RecyclerView (5) (0) | 2021.06.28 |
[AOS] Room + ViewModel + LiveData + RecyclerView (4) (0) | 2021.06.28 |
[AOS] Room + ViewModel + LiveData + RecyclerView (3) (0) | 2021.06.28 |