DataBinding에는 여러 고급기능이 있습니다. 오늘은 그 기능들을 정리해 볼까 합니다.
표현식
DataBinding에서는 xml에서 단순히 객체에 접근하여 값만 가져오는것이 아닌 간단한 표현식이나 함수의 사용을 지원하고 있습니다.
연산자의 지원
Mathematical, 수학 | + - / * % |
String concatenation, 문자열 결합 | + |
Logical, 논리 | && || |
Binary, 2진 연산 | & | ^ |
Unary, 단항 연산 | + - ! ~ |
Shift, 쉬프트 연산 | >> >>> << |
Comparison, 비교 연산자 | == > < >= <= (the < needs to be escaped as <) |
Grouping | () |
Cast | |
Array access, 배열 접근 | [] |
Ternary operator, 삼항 연산자 | ?: |
널 병합 연산자 | ?? |
이밖에도 String.valueOf() 같은 Java 또는 Kotlin의 기본 함수들을 사용할 수 있습니다. 그렇다면 다른 함수를 사용하고 싶다면 어떻게 해야 할까요? 해당 클래스를 임포트 해주어야 합니다.
import태그
XML에서 DataBinding을 사용할 때, import라는 태그를 지원합니다.
import 태그는 말 그대로 해당 클래스를 참조하여 프로퍼티나 메서드를 사용할 수 있게 합니다.
사용 방법은 간단합니다.
<data>
<import type="android.view.View"/>
<!-- 명칭이 겹친다면 별명을 지정해줄수 있음 -->
<!--<import type="android.view.View"
alias="Views"
/>-->
<import type="com.example.User"/>
<import type="java.util.List"/>
<variable name="user" type="User"/>
<variable name="userList" type="List<User>"/>
</data>
위의 코드처럼 data 태그 안에서 사용 가능하며, type에 참조할 클래스를 넣어주고, 이름이 겹친다면 alias에 별명을 입력할 수도 있습니다.
참조한 클래스는 variable 태그에서 변수의 타입으로 지정할 수 있으며, 캐스팅이나 메서드 호출에 사용할 수 있습니다. 컬렉션 또한 import를 통해 접근할 수 있습니다.
include 태그 바인드 속성 추가
XML에서 레이아웃을 include로 넣어줄 수 있습니다. 이때 해당 레이아웃에서 DataBinding으로 변수가 필요할 때 bind 속성을 추가하여 변수를 넣어줄 수 있습니다.
<include
layout="@layout/contact_info"
bind:user="@{user}" />
onClick으로 이벤트 처리
onClick 속성은 해당 뷰를 눌렀을 때 발생하는 이벤트나 메서드를 지정할 수 있습니다. 이 경우, 두 가지로 나눌 수 있습니다. Method references는 변수에서 메서드를 가져오는 방식이고, Listener bindings는 람다식으로 지정하는 방식입니다.
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{handlers::onClickBtn}"/>
Method references의 경우, 함수에 접근하는 방식입니다.
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> handlers.onSaveClick(task)}"/>
Listener bindings의 구현입니다. 이 경우, 매개변수를 줄 수 있다는 장점이 있습니다.
데이터변경을 감지
앱 개발 시 데이터 변경을 감지할 수 있는 observable한observable 한 데이터 객체가 있습니다. 이 경우, 코드에서와 마찬가지로 UI에 바인딩되고 데이터 객체의 속성이 변경되면 UI가 자동으로 업데이트됩니다. observable 한 데이터는 여러 종류가 있습니다. Observable 클래스도 있으며, LiveData나 Flow도 있습니다. 이때 LiveData와 Flow는 LifeCycleOwner를 지정하면 라이프사이클을 인식하여 UI가 화면에 표시될 때만 트리거 되게 할 수 있습니다.
// Specify the current activity as the lifecycle owner.
binding.lifecycleOwner = this
ViewStub
ViewStub은 레이아웃의 일부를 지연 로딩할 때 사용하는 매우 가벼운 뷰입니다. DataBinding을 사용하여 ViewStub을 포함하는 방법은 다음과 같습니다.
<ViewStub
android:id="@+id/viewStub"
android:layout="@layout/stub_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
val viewStubBinding: StubLayoutBinding = DataBindingUtil.inflate(layoutInflater, R.layout.stub_layout, viewStub, false)
viewStub.setOnInflateListener { stub, inflated ->
val binding = DataBindingUtil.bind<StubLayoutBinding>(inflated)
binding?.user = user
}
viewStub.inflate()
바인딩 어댑터
바인딩 어댑터를 사용하면 XML 속성을 커스터마이즈하여 사용할 수 있습니다. 바인딩 어댑터는 @BindingAdapter 애노테이션을 사용하여 정의합니다.
@BindingAdapter("imageUrl")
fun loadImage(view: ImageView, url: String) {
Glide.with(view.context)
.load(url)
.into(view)
}
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:imageUrl="@{user.profileImageUrl}"/>
양방향 데이터 바인딩
양방향 데이터 바인딩은 데이터 변경이 UI에 반영되고, UI 변경이 데이터에 반영되도록 합니다. 이를 위해 @= 연산자를 사용합니다.
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={user.name}"/>
이경우 code에서도 감지를할수있게 Observable 한 값을 넣는 것이 좋습니다.
바인딩 어댑터+ 양방향 데이터 바인딩
바인딩 어댑터와 양방향 데이터 바인딩을 함께 사용하여 커스텀 속성의 값을 읽고 쓸 수 있습니다.
@BindingAdapter("app:userAge")
fun setUserAge(view: EditText, age: Int) {
view.setText(age.toString())
}
@InverseBindingAdapter(attribute = "app:userAge") // 변경이되었을경우 원본데이터에 이함수의 반환값을 넘겨줌
fun getUserAge(view: EditText): Int {
return view.text.toString().toIntOrNull() ?: 0
}
@BindingAdapter("app:userAgeAttrChanged")
fun setUserAgeListener(view: EditText, listener: InverseBindingListener) {
view.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
listener.onChange()
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})
}
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:userAge="@={user.age}"/>
참고
https://velog.io/@jjddww/AAC-Data-Binding-3
https://jaejong.tistory.com/98
'안드로이드 > AAC(Android Architecture Components)' 카테고리의 다른 글
[AAC] Navigation의 정의와 적용 (0) | 2024.06.10 |
---|---|
[AAC] Lifecycle 정의와 활용 (0) | 2024.06.07 |
[AAC] LiveData의 정의와 사용 (0) | 2024.06.06 |
[AAC] DataBinding의 정의와 적용 (0) | 2024.06.04 |
왜 앱개발자 공고 AAC사용 경험을 우대할까? (0) | 2024.06.03 |