개요
기존의 사용하던 viewBinding에서 최근에는 DataBinding을 사용하는 방향성으로 바뀌고 있습니다.
저도 코드를 viewBinding을 사용해서 작성했는데, 최근에 DataBinding을 사용했고, 느낀 점과 공부한 점을 적을 예정입니다.
DataBinding
dataBinding의 사전적 정의는 이러합니다.(공식문서)
데이터 결합 라이브러리는 프로그래매틱 방식이 아니라 선언적 형식으로 레이아웃의 UI 구성요소를 앱의 데이터 소스와 결합할 수 있는 지원 라이브러리입니다.
즉 setText와 같이 코드적으로 UI 구성요소에 연결하는것이 아닌 어떠한 선언적 형식으로 UI 구성요소에 데이터를 연결한다고 해석할 수 있습니다.
Databinding은 viewModel과 LiveData와 함께 사용할 때 그 강점이 극대화됩니다.
viewModel에서 data가 변경됨과 동시에 Databinding을 통해서 UI 구성요소로 변경된 데이터의 상태를 연결할 수 있습니다.
build gradle(app)
buildFeatures {
dataBinding = true
}
build gradle (app)에 dataBinding을 추가해줍니다.
기존의 viewBinding을 사용하셨다면 익숙한 형식일 거 같습니다.
이렇게 DataBinding을 선언했다면, 레이아웃의 설정은 DatabindingLayout으로 변경해줘야 합니다.
이는 정말 간단합니다.
맥 유저라면 option + enter, 윈도 유저라면 alt + enter를 입력하시면 자동으로 dataBinding layout으로 바꿔줍니다.
dataBinding layout으로 바뀐 형태입니다.
특징은 layout이라는 규모 뷰로 감싸고, 안의 연결할 data들을 명시해 주면 됩니다.
dataBinding과 viewModel을 자주 연결해서 사용하기 때문에, 저 같은 경우는 다음과 같이 사용합니다.
그럼 xml 코드 내에서 viewModel은 해당 경로에 있는 클래스를 의미합니다.
하지만 선언된 변수를 사용하려면 데이터와 뷰를 결합해줘야 합니다.
private fun setBinding(){
binding.view=this
binding.viewModel = viewModel
binding.lifecycleOwner=viewLifecycleOwner //필요.
}
다음과 같이 DataBinding을 사용하는 Activity나 Fragment에서 binding을 선언하고,
binding에서 사용되는 view, viewModel을 연결해줘야 합니다.
그리고 Import문을 통해서 View를 Import 해서 람다식의 View.Gone, View.Visible 등도 설정할 수 있습니다.
이렇게 선언하면 xml에서 선언한 변수들과 import문을 사용할 수 있습니다.
액티비에서 사용되는 Databinding입니다.
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
프래그먼트에서 사용되는 Databinding입니다.
_binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
xml에서 사용되는 표현식에는 여러 가지 연산자와 키워드를 사용할 수 있습니다.
- 산술 + - / * %
- 문자열 연결 +
- 논리 && ||
- 바이너리 & | ^
- 단항 + -! ~
- 전환 >> >>> <<
- 비교 == > < >= <=(<는 <으로 이스케이프 처리해야 함)
- instanceof
- 그룹화 ()
- 리터럴 - 문자, 문자열, 숫자, null
- 변환
- 메서드 호출
- 필드 액세스
- 배열 액세스 []
- 삼항 연산자?:
다음과 같이 사용할 수 있습니다.
android:visibility = "@{viewModel.isssueList.size >= 5 ? View.VISIBLE, VIEW.GONE}"
android:text="@{viewModel.issue.title"}
DataBinding은 null 포인터 예외를 방지할 수 있습니다.
android:text="@{car.name}"
일 경우 car가 null이라면 car.name에 null이 기본으로 할당됩니다.
즉 car가 null이라면 해당 textView는 내용이 비어있는 겁니다.
car.name 이 아니라 car.price와 같은 int형의 경우도 car가 null이라면, 기본값인 0으로 할당됩니다.
또 다른 사용방법으로는 동일한 Layout의 다른 UI 구성요소를 참조할 수 있다는 뜻입니다.
예를 들면 editText에서 입력한 텍스트를 따른 텍스트뷰에 적용하고 싶을 경우가 있겠네요
<EditText
android:id="@+id/example_text"
/>
<TextView
android:id="@+id/copy_example"
android:text="@{exampleText.text}"/>
다음과 같이 TextView는 EditText를 참조하고 있습니다.
여기서 참조하는 view의 아이디는 반드시 카멜 케이스로 표기해줘야 합니다.
Databinding의 또 다른 장점은 결합어뎁터를 통해서 메서드를 호출하거나, 속성값을 설정할 수 있습니다.
BindingAdapter를 어노테이션 하고 해당 함수를 설정하면 xml 내에서 변수처럼 사용할 수 있습니다.
예를 들어 저는 recyclerView에서
- 아이템의 개수가 5개보다 많을 때, 미리 보기 형태로 아이템 하나의 크기인 200으로 높이를 고정.
- 아이템의 개수가 5개 이하일 땐, 미리 보기 지원 x , 아이템을 전부 보여줌.
- 아이템이 없을 때 view를 보여주지 않을 예정입니다.
@BindingAdapter("ResultVisible")
fun bindFilterResultIssueVisible(recyclerView: RecyclerView, itemList: List<Issue>) {
if (itemList.isNotEmpty()) {
val layoutParams = recyclerView.layoutParams
if (itemList.size <= 5) {
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
} else {
layoutParams.height = 200
}
recyclerView.visibility = View.VISIBLE
} else {
recyclerView.visibility = View.GONE
}
}
BindingAdapter로 선언한 "ResultVisible"은 xml 내에서 전역변수로 사용됩니다.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/result_recycler_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
ResultVisible="@{viewModel.issueResultList}"
이제 이런 식으로 ResultVisible에 내가 사용할 아이템을 변수로 넣어준다면 해당 아이템의 크기에 따라 UI의 상태가 바뀝니다.
더 자세한 내용은 공식문서를 통해서 확인하실 수 있습니다.
https://developer.android.com/topic/libraries/data-binding?hl=ko
느낀 점
우선 DataBinding을 사용하면서 느낀 점은 Activity나 Fragment에 UI의 상태를 변경하는 코드들을 작성하지 않아도 되는 장점이 있습니다. 해당 장점은 다른 사람들이 코드를 볼 때 Activity나 Fragment에서 UI 호출의 코드를 제외하고 핵심적인 코드를 확인할 수 있기 때문에 코드의 가독성이 정말 늘어난다고 느꼈습니다.
viewBinding을 사용하면 Activity나 Fragment에 UI 호출 코드가 엄청 많아서 함수로 분리를 하더라도, 코드의 양이 엄청 길었던 것을 감안하면 DataBinding은 효율적인 방법인 거 같습니다.
하지만 명백한 단점도 존재하는 거 같습니다.
우선적으로 DataBinding을 사용하면 클래스마다 BindingClass를 생성하게 됩니다.
이러한 생성이 크게 영향을 주지는 못할 수도 있지만, 앱의 파일이 많아질 때, 생성되는 BindingClass가 많아진다면,
당연하게 용량이 많아지고, 앱의 속도에 영향을 미칠 수 있다고 생각합니다.
그리고 개인적으로 느낀 단점은 코드 내에서 작성하는 것이 아닌 Xml에서 선언적 형식으로 작성되기에,
디버깅하는 것이 굉장히 어렵게 느껴졌습니다. 디버깅 메시지도 길고, 어떠한 오류인지 명확하게(?)는 코드 작성자에게 보여준다고 느낌을 받지 못해서 DataBinding을 사용할 때 람다식을 신중하게 작성해야 할 것 같다고 느꼈습니다.
하지만 이러한 단점에도, 요즘 추세는 viewBinding보다는 DataBinding을 선호하고 밀어주려는 방향인 거 같습니다.
무엇보다 UI호출의 코드가 줄어들고, LiveData을 통해서 UI와 Data의 상태를 일치시킨다는 장점이 엄청난 메리트라고 느꼈습니다.
'Skils > Android' 카테고리의 다른 글
[Android] - Jetpack Compose (1) | 2023.10.31 |
---|---|
[Android] - 다국어 지원, String.xml 이용하기 (1) | 2023.10.19 |
[Android] - Navigation Component (0) | 2023.09.03 |
[Android] - Context (0) | 2023.02.22 |
[Android] - Live Data (0) | 2023.02.12 |