1. DataBinding
Android Jetpack 라이브러리의 구성 요소이며, XML 파일에 Data를 연결(Binding)해서 선언적 형식으로 레이아웃의 UI 구성 요소를 데아터 소스와 결합할 수 있도록 도와주는 라이브러리이다.
2. DataBinding 사용하는 이유
App 로직과 레이아웃을 바인딩 시 필요한 글루 코드를 최소화 할 수 있다.
액티비티에서 findViewById를 작성하지 않아도 자동으로 View를 생성한다.
Data가 변경되면 자동으로 View를 업데이트 한다.
따라서 MVVM 아키텍쳐와 함께 사용하게 되면 여러 장점이 생기게 된다.
RecyclerView의 아이템 세팅 작업을 자동으로 한다.
XML 리소스만 보고도 View에 어떤 데이터가 들어가는지 파악 가능하다.
3. DataBinding 세팅
Gradle에서 다음 코드를 추가하기만 하면 DataBinding을 사용할 수 있다.
dataBinding {
enabled true
}
4. DataBinding 레이아웃 및 결합 표현식
Databinding을 사용하면 아래와 같이 레이아웃의 뷰에 변수를 연결할 수 있다.
아래와 같이 작성하면 라이브러리에서 자동으로 데이터 개체와 결합하는데 필요한 클래스를 자동으로 생성하게 된다.
데이터바인딩을 사용하기 위해 먼저 데이터바인딩을 사용할 레이아웃의 최상단에 Layout 태그로 감싸준다.
그 후 data 태그를 사용해 레이아웃에서 사용될 데이터바인딩 요소를 정의할 수 있다.
변수를 설정하기 위해서는 variable 태그를 사용해서 변수 이름과 변수 타입을 지정해주면 된다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="community"
type="com.example.myapplication.data.model.ResponseData" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DDDDDD"
android:orientation="vertical">
...
</LinearLayout>
</layout>
위 예제에서는 community라는 이름과 ResponseData 타입의 변수를 설정했다.
참고로 Response Data 클래스는 아래와 같이 작성했다.
data class ResponseData(
val USR_NM: String
)
다음으로는 레이아웃 내부에 @{ .. } 구문을 사용해서 데이터바인딩을 작성하면 된다.
아래 예제를 보면 community.USR_NM을 사용했는데 이는 위에서 설정한 community 변수의 데이터값 (USR_NM)을 텍스트뷰의 텍스트로 설정을 하겠다는 말이다.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@{community.USR_NM}"
android:textSize="20sp"
android:textStyle="bold" />
레이아웃에서 데이터바인딩을 작성했으면 액티비티에서 binding.community를 사용해 해당 변수에 접근이 가능하다.
위에서 community 변수 타입을 ResponseData로 설정했기 때문에 ResponseData("...")을 사용해서 community에 해당 타입의 값을 넣어주었다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
binding.community = ResponseData("Test")
}
그냥 R.id.textView의 text를 값에 넣어주거나 뷰바인딩을 사용해서 binding.textView.text = "..."를 사용하는 것이랑 큰 차이가 없어 보이지만 아래와 같이 data의 값이 많아지면 데이터 바인딩이 더 효율적이라는 것을 알 수 있다.
binding.community = ResponseData("text1", "text2", ..., "text100")
일일히 각각의 레이아웃에 데이터를 삽입하는게 아니라 데이터 타입에 맞는 객체를 자동으로 연결해주기 때문에 코드가 굉장히 간결해질 뿐더러, 다양한 레이아웃에서 하나의 데이터 객체만으로 재사용이 가능하기 때문에 직관적이다.
5. Observable 객체
Observable 객체는 데이터바인딩 된 객체의 값이 변경이 되면 해당 객체를 사용하는 곳에서 리스너를 통해 알림을 받고 동적으로 변경해준다.
class User : BaseObservable() {
@get:Bindable
var firstName: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.firstName)
}
@get:Bindable
var lastName: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.lastName)
}
}
BaseObservavle()을 참조하는 클래스에서 @get:Bindable Annotation과 함께 변수의 변경사항을 알려주는 setter를 작성해 리스너를 작성할 수 있다.
6. Binding Adapter
바인딩 어댑터는 데이터바인딩을 좀 더 효율적으로 사용할 수 있도록 제공하는 어댑터이다.
간단하게 예를 들자면 레이아웃에서 속성으로 android:text = 를 사용해서 레이아웃의 텍스트를 설정하는 것처럼,
바인딩 어댑터를 통해 레이아웃의 속성을 직접 설정하여 해당 작업을 수행할 수 있도록 하는 기능이다.
더 쉽게 예제를 들고 와봤다.
위와 같은 레이아웃을 제작했다고 가정해보자.
레이아웃은 리스트로 구성되어 있는데, 사용자가 작성한 리스트에만 수정, 삭제 버튼이 보이게 하고 싶다고 한다.
사용자의 아이디 값을 비교 후 해당 레이아웃의 작성자가 사용자와 일치하면 수정 삭제 버튼을 visible 처리하면 된다.
데이터바인딩를 사용하지 않을 때 어떻게 구현하는지 먼저 생각해보면 리스트 어댑터에 해당 로직을 구현할 것이다.
그러면 해당 레이아웃을 사용하는 어댑터에서 매번 똑같은 코드를 작성하게 될 것이다.
바인딩 어댑터를 사용한다면 아래의 isSameId 속성 하나만 적으면 적용이 된다.
isSameId에는 User ID값을 넣었다.
<TextView
android:id="@+id/edit_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:isSameId="@{comment.USR_ID}"
android:text="수정"
app:layout_constraintEnd_toStartOf="@id/edit_delete"
app:layout_constraintTop_toBottomOf="@id/edit_content"/>
isSameId는 아래의 바인딩 어댑터를 작성하면 된다.
object BindingAdapter {
@BindingAdapter("android:isSameId")
@JvmStatic fun visibleComment(textView: TextView, USR_ID: Int) {
if (USR_ID == 5) {
textView.visibility = View.VISIBLE
} else {
textView.visibility = View.GONE
}
textView.visibility = if(USR_ID ==5) View.VISIBLE else View.GONE
}
}
@BindingAdapter("android:isSameId")를 사용해 레이아웃 속성을 제작할 수 있다.
그 아래에는 실행하고 싶은 함수를 적고 레이아웃 타입(TextView)와 받아오는 객체(USR_ID)를 파라미터로 받아와 로직을 실행시켜주면 된다.
이렇게 하면 isSameId 속성에 User ID 값만 넣는 작업으로 자동으로 로직을 실행시켜준다.
응용하면 다음과 같이 이미지뷰에 이미지 URL값만 넣어주면 자동으로 URL을 이미지로 변환시켜주는 어댑터를 생성해 네트워크를 통해 이미지 URL을 받아오는 곳에서 간단하게 사용할 수 있다.
//레이아웃
<ImageView
android:layout_width="90dp"
android:layout_height="90dp"
android:scaleType="centerCrop"
android:background="@drawable/box_layout"
android:clipToOutline="true"
app:imageUrl="@{community.COM_IMG1}"
app:layout_constraintBottom_toBottomOf="@id/content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/guideline2"
app:layout_constraintTop_toTopOf="parent"/>
//바인딩어댑터
@BindingAdapter("app:imageUrl")
@JvmStatic fun loadImage(imageView: ImageView, url: String?) {
if (url.isNullOrBlank()) {
imageView.visibility = View.GONE
} else {
imageView.visibility = View.VISIBLE
Glide.with(imageView.context)
.load(url)
.into(imageView)
}
}
바인딩 어댑터는 활용만 잘하면 굉장히 편해지는 기능이기에 자세히 알아두면 좋을 것 같다.
7. 양방향 데이터 바인딩
지금까지 레이아웃에 데이터를 단순히 적용시키는 단방향 데이터바인딩을 봤지만 양방향 데이터바인딩도 제공을 한다.
양방향 데이터바인딩은 @={..} 기호를 사용하여 데이터 변경사항을 받는 동시에 업데이트를 수신한다.
<CheckBox
android:id="@+id/rememberMeCheckBox"
android:checked="@={viewmodel.rememberMe}"
/>
체크박스가 체크될 때마다 viewmodel의 rememberMe라는 값을 수신하는 예제이다.
class LoginViewModel : BaseObservable {
// val data = ...
@Bindable
fun getRememberMe(): Boolean {
return data.rememberMe
}
fun setRememberMe(value: Boolean) {
// Avoids infinite loops.
if (data.rememberMe != value) {
data.rememberMe = value
// React to the change.
saveData()
// Notify observers of a new value.
notifyPropertyChanged(BR.remember_me)
}
}
}
viewmodel을 보면 @Bindable을 사용하고 getter와 setter가 있다.
getter를 통해 레이아웃에서 체크 여부를 수신하고 setter에서 체크 값을 저장한 후 레이아웃 데이터바인딩 값의 변화를 알려주고 있다.
이런식으로 양방향으로 데이터바인딩을 사용해 레이아웃 업데이트에 즉각적으로 반응할 수 있다.
그 외 데이터 바인딩에 관한 상세한 내용은 안드로이드 공식 페이지에서 참조하여 사용하면 된다.
데이터바인딩을 주제로 작성한 김에 하고싶은 말을 끄적여본다.
안드로이드에서 데이터바인딩은 정말 편한 기술이 맞긴 하다.
하지만 이는 Compose가 나오기 전, 선언형 UI에 목말라있던 안드로이드가 선언형 스타일인 데이터바인딩을 선보인 것이다.
정말 많은 기업에서 데이터바인딩을 적극적으로 활용하고 있지만 현재 컴포즈가 점점 자리잡고 있는 시점에서 데이터바인딩은 사라지고 있는 추세이다.
레이아웃을 XML로 구성하는 앱이면 데이터바인딩은 정말 좋은 기술이지만 컴포즈가 등장함에 따라 구글도 데이터바인딩에 손을 떼는 추세이다...
본인도 컴포즈를 준비하고 있기에 데이터바인딩을 일부러 손 대지 않았지만 현업에서는 데이터바인딩을 사용중이기에 정리해본다.
결론은 컴포즈 짱짱맨
'Android' 카테고리의 다른 글
[Android] Version Catalog (0) | 2024.06.17 |
---|---|
[Android] Serializable, Parcelable (0) | 2023.07.02 |
[Android] Paging3 Frame Drop Issue (0) | 2023.04.23 |
[Android] Hilt - Android DI Library (0) | 2023.04.15 |
[Android] Room DB 사용해보기 (0) | 2023.04.08 |