[Android] View Binding
Android에서는 현재 UI를 그리기 위해 XML을 사용하고 있습니다. (Compose는 논외로 합니다.) XML에 정의한 View widget들을 제어하기 위해서는 Java/Kotlin 코드로 작업을 해야하죠. 코드에서 해당 view들의 reference를 얻기 위해서 일반적으로 아래와 같은 방법을 사용합니다.
// Java
Button button = (Button) findViewById(R.id.button)
// Kotlin
val button = findViewById<Button>(R.id.button)
하지만 이미 Android 앱 개발을 좀 해보신 분이라면 아시겠지만 위와 같은 방식은 단점이 좀 있죠.
- 당연하게도 reference 얻어오는 방식이 불편합니다. 1~2개면 모르겠지마, 10개가 넘어가면 이거 관리하는 것도 살짝 짜증납니다. 가끔 id를 잘못 넘겨줘서 에러가 발생하기도 하고요.
- findViewById 함수 자체가 비용이 높은 함수로 유명합니다.
이러한 단점들을 극복하고자 여러 시도, 라이브러리들이 있었습니다. 대표적으로 ButterKnife가 있었죠.
Kotlin으로 넘어와서는 KTX를 통해 View binding이 혁신적으로 바뀌기도 했습니다. 단 하나의 import 문만으로도 xml에 정의한 id 값을 통해 바로 접근이 가능했죠. (물론 이 방법은 잠재적인 버그가 있기 때문에 실제 상용 서비스에서는 피하는 방식같습니다.)
그래서 본 포스팅에서는 구글에서 제시한 새로운 View Binding 기법을 소개하고자 합니다. 공식 문서에 한 페이지의 그리 길지 않는 분량으로 작성되어 있기 때문에 참고하시면 됩니다.
Warning
본 포스팅에서 소개하는 View Binding은 Android Studio 3.6 Canary 11 이상에서만 사용 가능합니다… ㅠㅠ
View Binding 활성화
build.gradle 파일을 열고 아래와 같이 view binding을 활성화합니다.
android {
...
viewBinding {
enabled = true
}
}
아래와 같은 XML이 있다고 가정하겠습니다. (activity_main.xml)
<ConstraintLayout ...
tools:viewBindingIgnore="true">
<TextView android:id="@+id/tvName"
... />
<Button android:id="@+id/btnLogin"
... />
</ConstraintLayout>
먼저 Root의 ConstraintLayout에 적용된 viewBindingIgnore 속성을 살펴보면 true로 설정할 경우 binding 클래스를 생성하는 동안 해당 레이아웃 파일은 무시되게끔 할 수 있습니다.
자동으로 생성되는 Binding 클래스의 이름은 XML 파일 이름을 따라 다음과 같이 생성됩니다: ActivityMainBinding
따라서 아래와 같이 원하는 View의 reference를 참조할 수 있습니다.
class MainActivity: Activity() {
private lateinit var binding: ResultProfileBinding
@Override
fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
binding = ActivityManBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tvName.text = viewModel.name
binding.btnLogin.setOnClickListener { viewModel.login() }
}
}
장점
공식 문서에서도 언급하듯이
위와 같이 자동으로 생성된 ViewBinding 클래스를 사용하기 때문에 잘못된 id를 넣어 발생할 수 있는 NPE 문제나 View Type의 mismatch 발생 가능성이 낮아지게 되는 장점이 있습니다.
하지만 한 가지 단점?이 있는 것 같습니다.
공식 문서에는 View Binding과 Data Binding에 대한 차이로 언급되어 있는데 이 둘을 같이 사용하기는 어려워 보입니다. View binding은 layout 태그를 지원하지 않기 때문입니다.