연결된 특정 두 데이터 혹은 소스를 일치시키는 기법을 말한다.
특정 데이터를 화면에 보여줘야 한다면, 그 데이터가 변경됨에 따라 화면에 보여지는 데이터도 변경되어야 하는데, 그 때 두 데이터를 여러가지 방법을 통해 묶어주는 개념이다. 여기서 가장 중요한 point는 '눈에 보이는 데이터와 실제 존재하는 데이터의 싱크를 맞추는 것'이다.
그렇다면 안드로이드에서 data binding이 무엇인지 먼저 살펴보자.
안드로이드의 Data Binding은 android jetpack의 라이브러리 중 하나로, 안드로이드의 xml 리소스에 data를 부착하는 것을 의미한다.
kotlin 코드 내에서 view를 호출하기 위해 따로 각 뷰를 불러오는 것이 아니라 DataBindingUtil과 같은 object를 이용해 binding class를 저장하고, 그 class를 이용해 각 뷰를 이용할 수 있어, 잘못된 id를 불러오는 실수 등을 줄일 수 있다.
abstract class CommonFragment<T : ViewDataBinding>(@LayoutRes private val layoutId: Int) :
Fragment() {
private var _binding: T? = null
protected val binding: T get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = DataBindingUtil.inflate(
layoutInflater,
layoutId,
null,
false
)
binding.lifecycleOwner = this
return binding.root
}
}
databinding을 적용한 xml 리소스의 경우 자동으로 완성되는 BindingClass를 통해 그 class를 사용할 수 있게 작성할 수 있다. 위와 같이 작성하면 onViewCreated와 같은 곳에서 binding.viewId(자동으로 생성된 BindingClass)로 코드를 작성해서 사용할 수 있게 된다.
xml에서 존재하지 않는 viewId는 class 변수로도 존재하지 않기 때문에 syntax error를 뱉어준다. 이를 통해 xml에서 작성한 모든 뷰를 이전보다 안전하게(null-safety) 사용하는 것이 가능해진다. findViewById가 null-safety하지 못한 단점에 대한 불만과 KTX(Kotlin Android Extensions)가 deprecated된 시점부터 압도적인 장점이 되었다.
물론 binding 역시 IO 코루틴 내에서 작업하다가 다시 Main 코루틴으로 변경해서 UI작업을 하는 형태로 코드를 작성하게 되었을 때 UI의 생명주기가 살아있는 상태임을 보장할 수 없을 때 NPE가 발생하긴 한다. 하지만 정상적인 코드 형태에서는 null-safety하다고 여긴다.
LiveData와 observe 변수를 함께 사용하는 경우, 데이터의 변경이 일어날 때 자연스럽게 연결된 UI도 업데이트 시켜 UI와 데이터의 바인딩이 보장된다. (사실 이 기능이 없다면 데이터바인딩이라는 이름일 수 있을지 고민이 들긴 함.)
<data></data>
내부에 변수 작성xml에 <data></data>
내부에 변수를 작성하는 것으로 xml에서 사용할 데이터를 kotlin class 내부에 의지하지 않고 작성할 수 있다.
<?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>
<variable
name="listViewModel"
type="com.myApplication.android.viewmodel.ListViewModel" />
</data>
<!-- layout code writing -->
</layout>
위와 같이 코드를 작성하면 <variable>
내부의 name을 통해 데이터를 작성할 수 있게 됩니다.
android:text="@{listViewModel.listName}"
위와 같은 방식으로 코드를 사용할 수 있는데, 이를 이용하면 추가적인 작업 없이 view에 data를 표현해줄 수 있다. 더 세부적인 상세 내용을 적는 등의 작업은(금액에 ,
를 찍는다거나 하는 다른 가공 처리가 필요한 경우) bindingAdapter를 이용해서 작업을 진행할 수 있다. 이를 통해 뷰에서 직접 데이터를 관리하는 느낌과 한 곳에 위치한 데이터와 UI를 통해 전체적인 가독성을 상승시킬 수 있다.
android:text="@={viewModel.encouragementMessage}"
또한 위와 같이 EditText에서 @{
가 아니라 @={
로 시작하는 경우 양방향 데이터바인딩이 이루어져 EditText가 가진 변수와 @={}
안에 들어간 변수가 싱크를 유지하며 동일한 데이터로 매칭된다. 이처럼 UI내에서 변수를 가지게 되는 경우에는 양방향 데이터 바인딩을 사용할 수 있다.
이 때문에 앱의 기본적인 용량의 상승을 피하기 어렵고, 빌드의 속도가 느려져 전체적인 개발 속도에 영향을 미칠 수 있다.
기본적으로 XML 어디 라인에서 에러가 났습니다를 알려주는 경우도 분명 존재하지만, 특정 에러를 제외하고는 xml에서 에러가 나는 경우 전혀 다른 exception을 발생하는 등의 문제를 일으키기 때문에, 기존 code에서 작성하는 것 보다 더 세심한 주의가 필요하다. 또한 문제가 발생해도 찾기 어렵기 때문에 잘 살펴봐야 한다.
뷰 바인딩(View Binding)은 말 그대로 뷰를 바인딩(Binding: 묶어놓다.)하는 것이다. 레이아웃 XML 파일에 대한 액티비티 클래스를 정의하지 않고 자동적으로 뷰(View)에 대해 커넥션을 생성해주는 기능을 말한다.
build.gradle에서 뷰 바인딩 속성을 활성화시키면 해당 모듈에 있는 각 XML 레이아웃 파일에 대한 바인딩 클래스가 자동적으로 생성된다.
Null Pointer Exception
을 방지해, Null-safe를 보장한다.Data Binding과 View Binding은 동일하게 뷰를 직접 참조하는 바인딩 클래스를 생성한다.
참고
https://no-dev-nk.tistory.com/82
https://parkjh7764.tistory.com/150