기존에 작성했던 ViewBinding 포스트를 참고하면 이해가 더 빠를 것이다.
Data - View의 연결 작업을 레이아웃에서 처리할 수 있게 도와주는 라이브러리
DataBinding 은 ViewBinding이 하는 역할에 추가적으로 동적 UI 컨텐츠를 선언하고, 양방향 데이터 결합도 지원한다.
findViewById()
를 대체할 용도라면 ViewBinding을 사용하는 것이 옳다.직접 구현해보면서 어떤 부분이 좋은지 알아보도록 하자.
android {
buildFeatures {
dataBinding = true
}
}
ViewBinding 과 설정 방법이 거의 동일하다. 그러나, ViewBinding 과는 다르게 빌드하자마자 Binding 클래스가 생성되는 것은 아니다. 따로 XML에서 설정을 해주어야만 Binding 클래스가 생성된다.
data class User(
var nickname: String?,
var name: String?
)
위의 레이아웃과 동일하게 생성할 것이다.
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<!-- Databinding -->
<variable
name="user"
type="com.dongyang.android.mvvm_sample.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".EditUserProfileActivity">
<TextView
android:id="@+id/tv_nickname"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="30dp"
android:hint="edit your nickname"
android:text="@{user.nickname}"
android:textColor="@color/black"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_name"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:hint="edit your name"
android:text="@{user.name}"
android:textColor="@color/black"
android:textSize="20sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="30dp"
android:background="@color/black" />
<EditText
android:id="@+id/edt_nickname"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:hint="edit your nickname" />
<EditText
android:id="@+id/edt_name"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:hint="edit your name" />
<Button
android:id="@+id/btn_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:text="EDIT" />
</LinearLayout>
</layout>
기존에 알던 레이아웃 구조에서 조금 변화가 생긴 것을 알 수 있다.
<layout>
태그가 추가되었다.<data>
태그가 추가되었다.<layout>
태그의 경우 크게 어려운 점은 없고, 그저 추가만 해주면 된다. 그렇다면 주목해야 할 태그는 <data>
태그인데, 해당 태그 안에 <variable>
이라는 태그가 추가되었다. 어떤 역할을 맡는걸까?
위에서 이야기했던 Data - View 연결을 여기서 진행한다. type
에는 연결하고 싶은 데이터 클래스의 경로를 지정하고, name
에는 XML에서 사용할 이름을 설정해주면 된다. 위 소스를 통해, User
데이터 클래스에 접근이 가능해졌다.
사용 방법은 <TextView>
태그를 보면 알 수 있다. 변수를 @{}
구문안에 넣어 해당 데이터를 뷰와 바인딩할 수 있다. 위의 XML에서는 User
의 이름과 닉네임을 바인딩한 것을 확인할 수 있다.
추가적으로, 이 과정을 거치면 바인딩 클래스가 생성되며, 이름은 ViewBinding과 마찬가지로 카멜 표기론에 의거하여 지어진다.
list_fragment.xml
-> ListFragmentBinding
hoya_activity.xml
-> HoyaActivityBinding
class EditProfileActivity : AppCompatActivity() {
private val binding: ActivityEditProfileBinding by lazy {
ActivityEditProfileBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.btnEdit.setOnClickListener {
setUserData()
}
}
fun setUserData() {
val setNickName = binding.edtNickname.text.toString()
val setName = binding.edtName.text.toString()
/* ViewBinding
binding.tvName.text = setName
binding.tvNickname.text = setNickName
*/
val userData = User(setNickName, setName)
binding.user = userData // XML에 데이터 전달
}
}
XML의 text
를 액티비티에서 설정하는 것이 아니라, 오로지 전달만 해주는 모습을 확인할 수 있다. 지금은 그저 두 개의 TextView
라서 와닿지 않을 수 있지만 만약 10개 이상의 TextView
가 존재했고, 거기에 일일이 데이터를 넣어주어야 했다면 액티비티의 코드가 굉장히 난잡해졌을 것이다.
👀 현재는 EditText의 값을 받아와서 액티비티에서 받고 다시 XML로 전달하는 과정을 거치고 있지만, 더 자세히 파고들면 2-way binding 이라고 해서 EditText의 값이 변경되면 바로 TextView에 넣는 방법도 가능하다. 해당 포스팅은 기초적인 정보를 담고 있으므로 이 방법은 추후에 따로 작성하도록 한다.
구글 공식 문서에 기재되어 있는 표현식은 아래와 같다.
이 중에서 예시로 삼항 연산자를 사용해보도록 하자. 기존 유저 데이터 클래스에 gender
변수를 추가하고, 값이 0이면 "남성"을 출력하고, 1이면 "여성"을 출력하는 예시를 만들어보자. 우선, 데이터 클래스를 먼저 추가한다.
data class User(
var nickname: String?,
var name: String?,
var gender: Int?
) {
companion object {
const val GENDER_MALE: Int = 0 // 상수
const val GENDER_FEMALE: Int = 1 // 상수
}
}
...
<data>
<import type="com.dongyang.android.mvvm_sample.User"/>
<!-- 레이아웃 파일 내에서 클래스 참조 -->
<variable
name="user"
type="com.dongyang.android.mvvm_sample.User" />
</data>
...
<TextView
android:id="@+id/tv_gender"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="5dp"
android:hint="edit your gender"
android:text="@{(user.gender == User.GENDER_MALE) ? "남성" : "여성"}"
android:textColor="@color/black"
android:textSize="20sp"
android:textStyle="bold" />
android:text
부분을 보면 삼항 연산자를 사용한 것을 볼수 있다. 텍스트에 String
형태로 넣기 위해서 원래는 큰 따옴표를 넣어야 하지만, 이미 큰 따옴표를 적은 상태이기 때문에 "
을 이용하여 큰따옴표를 따로 붙여주도록 한다.
이렇게 하면 아래와 같은 실행 결과를 얻을 수 있을 것이다.
리사이클러뷰에서 사용할 때도 크게 다른 점은 없다. 어댑터에서 아래와 같이 설정하면, 데이터바인딩이 적용되는 것이다.
class UserRecyclerViewAdapter(
) : RecyclerView.Adapter<UserRecyclerViewAdapter.ViewHolder>() {
private var items = listOf<UserProfile>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = UserlistBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
/* ViewBinding
holder.userId.text = item.id.toString()
holder.userName.text = item.name
holder.userPhone.text = item.phone
holder.userAddress.text = item.address
*/
holder.setData(item)
}
override fun getItemCount(): Int = items.size
inner class ViewHolder(private val itemBinding: UserlistBinding) : RecyclerView.ViewHolder(itemBinding.root) {
fun setData(userProfile : UserProfile) {
itemBinding.item = userProfile
}
/* ViewBinding
val userId = itemBinding.itemId
val userName = itemBinding.itemName
val userPhone = itemBinding.itemPhone
val userAddress = itemBinding.itemAddress
*/
}
}
한 눈에 보아도 주석을 제외하고 보면 코드가 줄어든 것을 확인할 수 있다.
참고 및 출처