선언적 형식으로 레이아웃의 UI 구성요소를 앱의 데이터 소스와 결합할 수 있는 지원 라이브러리
plugins {
...
//@를 통한 애너테이션 프로세싱
id 'org.jetbrains.kotlin.kapt'
}
...
android {
...
//Databinding 설정하기
dataBinding{
enabled = true
}
기존 선언한 viewGroup 바깥으로 layout 태그를 감싸고, 사용할 data 객체를 variable로 선언한다.
<layout>
<data>
<variable
name="user"
type="com.ssafy.databinding.User" />
</data>
layout 밑에 xml에 들어가는 데이터를 name과 type(dto도 가능)을 넣어준다.
해당 데이터를 xml에 넣는 방법은
android:text="@{user.firstName, default=`Hello`}"
위처럼 @로 감싸준다.
// binding = ActivityMainWithDatabindingBinding.inflate(layoutInflater)
// setContentView(binding.root)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main_with_databinding)
기존의 뷰 바인딩을 하던 방식대로 해도 되고
dataBindingUtil을 써서 해도 된다
그리고 xml안의 user를 binding.user로 접근하여 데이터를 주고 받는다.
binding.user = User("신", "사임당")
actvity안의 function을 가져올 수도 있다
<variable
name="activity"
type="com.example.databinding.MainActivityWithDataBinding" />
variable로 해당 액티비티를 가져오고
android:onClick="@{activity::onButtonClick}"
::
를 구분자로 안의 함수를 호출할 수 있다.
물론 activity에서 activity 인자로 자신을 전달해줘야 한다.
activity = context as MainActivity
데이터 바인딩 과정에서
android:text="@{user.lastName == `` ? `empty` : user.lastName}"
와 같이 표현식을 사용하여 데이터값을 넣는 경우가 꽤 있기 때문에
https://developer.android.com/topic/libraries/data-binding/expressions?hl=ko#expression_language
를 참고하자.
list-item.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="activity"
type="com.ssafy.databinding.MainActivity" />
<variable
name="youtubeDto"
type="com.ssafy.databinding.YoutubeDto" />
</data>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="15dp"
android:paddingBottom="15dp"
android:onClick="@{activity::onClickListener}">
<ImageView
android:id="@+id/thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:imageDrawable = "@{youtubeDto.image}"
android:adjustViewBounds="true"
tools:src="@drawable/image01"/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="15sp"
android:text="@{youtubeDto.title}"
tools:text="Youtube1"/>
</LinearLayout>
</layout>
위처럼 데이터를 xml 상에서 바인딩 해준다.
이를 통해
inner class ViewHolder(private val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) {
//binding을 객체로 받아 데이터와 연결시켜준다.
fun bind(item: YoutubeDto) {
binding.apply {
youtubeDto = item
activity = context as MainActivity
}
}
}
adapter의 코드를 줄일 수 있다.
app:imageDrawable = "@{youtubeDto.image}"
를 보면 youtubeDto에 있는 drawable 객체를 전달하고 있다.
이 imageDrawable이라는 이름은 내가 만든 binding Adapter에서 온다
@BindingAdapter("imageDrawable")
fun bindImageFromRes(view: ImageView, drawable: Drawable?) {
view.setImageDrawable(drawable)
}
++ src안에 drawable을 직접 줘도 됨!!
android:src="@{youtubeDto.image}"
위처럼 해도 된다. 따라서 위 예제에서는 binding adapter가 큰 의미 없을 수도 있지만,
gilde 처리등을 하는 등의 작업이 추가적으로 들어가면 binding adapter를 사용해서 받은 데이터를 변형하거나 추가작업을 해줄 수 있다.
데이터의 변경 사항을 감지하고 알려주는 객체
class YoutubeDto(val image: Drawable, val title: String) : BaseObservable() {
@get:Bindable
var clicked: Boolean = false
set(value) {
field = value
notifyPropertyChanged(BR.clicked) // BR : Binding된 Resource ID가 관리되는 Class
}
fun onClickListener(view: View) {
Toast.makeText(view.context, "Clicked: $title", Toast.LENGTH_SHORT).show()
clicked = when(clicked){
false -> true
true -> false
}
}
}
@get:Bindable
var clicked: Boolean = false
set(value) {
field = value
notifyPropertyChanged(BR.clicked) // BR : Binding된 Resource ID가 관리되는 Class
}
에서 clicked가 바뀔 때마다 notfiyPropertyChanged(BR.clicked)에서
BR : Binding된 Resource ID가 관리되는 Class의 clicked가 바뀌었음을 알려
xml의
android:background="@{youtubeDto.clicked ? @color/black : @color/white }"
바뀐 youtubeDto.clicked대로 background가 다시 적용된다.
<data>
<variable
name="textDto"
type="com.ssafy.databinding.TextDto" />
</data>
<!-- 값을 assign 하려면 "="이 필요-->
<EditText
android:id="@+id/edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={textDto.name}"
/>
물론 activity에서 textDto를 초기화해줘야 한다.
binding.textDto = TextDto()