[Android] View Binding

dEpayse
9 min readFeb 8, 2021

--

이번 포스트에서는 layout xml에서 만든 View들을 어떻게 source code에서 사용할 수 있는지에 대해 알아보려고 한다. 본 포스트에서는

  • findViewById() 함수를 직접 이용하는 방법
  • Kotlin synthetics 기능을 이용한 방법
  • View Binding 기능을 이용하는 방법

세 가지에 대해 알아보고 비교해보려고 한다.

findViewById() 를 통한 객체화

Android Studio에서 Activity를 생성하고 나면 layout xml 파일과 layout을 보여주는 kotlin 파일(.kt)이나 java 파일(.java)이 생성된다. kotlin이나 java 파일에서 layout xml 파일에 있는 View들을 조작하려면 Fig1과 같이 객체화하여 객체로서 View를 다뤄야한다.

Fig1. findViewById()

kotlin 파일에서 layout xml 파일의 View를 사용하려면

  1. layout xml의 View에 id를 지정해 준다.
  2. findViewById 함수로 xml의 View를 객체화한다.

위와 같은 방식으로 할 수 있다. 먼저 layout xml에서 View에 id를 지정해주는 방법은 “@+id/아이디이름”과 같은 형식으로 한다. “@”의 의미는 “~에”라는 위치의 의미이고, “+”가 붙은 것은 id를 관리하는 클래스에 새로운 아이디를 추가하겠다는 뜻이다. 단순히 “@id/아이디이름” 과 같은 형식도 존재하는데, 이는 id를 추가하지 않고 참조하겠다는 의미이기 때문에 여기서는 “+”도 반드시 붙여줘야한다. kotlin파일에서 리소스를 참조하는 방법은 “@”가 아닌 “R.”로 시작한다. 또한 참조하는 View와 형식이 맞아야 한다. 예를 들어 TextView는 TextView객체로, Button은 Button 객체로 만든 것과 같다.

그러나 이와 같은 방식은 몇 가지 혼란이나 오류를 야기할 수 있고, 모든 뷰를 일일이 객체화해주어야 하기 때문에 코드 또한 길어지는 경우가 생긴다. 이렇게 반복적으로 작성해야하는 코드를 boilerplate code라고 한다. 또, layout의 View 타입과 kotlin 파일에서 findViewById<“이 곳”>에 들어가는 타입이 다르거나, kotlin파일에서 findViewById<>(“이 곳”)에 들어가는 id가 존재하지 않는 경우나, 다른 layout에 같은 id가 있는 경우 등이 그렇다. 이런 경우의 몇 가지 문제점을 해결할 수 있는 기능이 kotlin-android-extensions 의 synthetics 이다.

kotlin android extensions — synthetics

***이 기능은 2021년 중으로 지원이 중단될 예정이라고 합니다. View Binding 이해를 위한 흐름에 포함한 글임을 알립니다.***

위와 같이 기능을 더 이상 사용할 수 없기 때문에 사용 방법에 관한 내용은 생략하려고 한다. 그러나 kotlin android extensions의 synthetics 기능은 안드로이드 개발을 굉장히 편리하게 해준 것 중 하나였다. 그 기능은 Source code에서 findViewById()함수를 이용하지 않아도 layout xml의 id만 있으면 id를 통해 객체로 사용할 수 있는 것이다.

Fig2. Kotlin Android Extension의 synthetics을 이용한 객체화

Fig2Fig1과 비교했을 때 findViewById()를 통해 객체화하는 부분이 없어져서 코드가 간단해진 것을 볼 수 있다. import 부분을 봐도 달라진 부분이 보이는데, android.widget의 TextView와 Button이 없어지고 kotlinx.android.synthetic의 하위 부분이 추가된 것을 볼 수 있다. 그럼 이 편리한 기능이 왜 지원 중단이 되는 것일까?

  1. Kotlin만 사용할 수 있는 기능이다.
  2. null safety를 보장하지 않는다. (compile time safety를 보장하지 않는다.)

1번은 별도의 해석이 필요하진 않아보인다. 2번에 관한 예를 들어보자면, Fig2의 Binding.kt에서 textView와 button 객체는 activity_binding xml파일에 존재하는 것이고, 따라서 오류도 발생하지 않고 잘 동작한다. 그러나 새로운 layout 파일을 만들어서 내부의 뷰에 id를 textView2 로 지정해준 경우를 생각해보자. 만약 Binding.kt에서 textView2를 textView나 button 객체처럼 사용한다면, 컴파일 타임 오류가 발생하지 않는다(빨간 밑줄이 보이지 않고, 컴파일이 성공적으로 된다.). 그러나 이 경우 textView2가 inflate되지 않았기 때문에 런타임에 IlligalStateException(null 오류)이 발생하여 앱이 강제 종료된다. 이렇게 컴파일 타임에 오류가 발생되지 않는다면 오류를 찾는데 더 많은 시간을 소비해야한다. Fig3은 이 예시의 경우를 나타낸 것이다.

Fig3. Null safe 하지 않은 Kotlin Android extension synthetics

View Binding

***View Binding은 Android Studio 버전 3.6이상부터 사용가능 합니다.***

View Binding을 사용하면 Fig4와 같이 View 객체를 사용할 수 있다.

Fig4. View Binding 사용하기

위의 findViewById() 함수로 View를 객체화하는 경우는 boilerplate code가 발생하고, kotlin synthetics를 사용하면 null safety가 보장되지 않지만 이 방법을 이용하면 이런 문제점이 해결된다. 또한 java언어로 작성해도 가능한 방법이므로 많은 문제들이 해결된다.

View Binding 사용법

  1. 모듈 수준의 build.gradle 파일에 viewBinding 추가하기

Fig4와 같이 View Binding을 사용하려면 우선 build gradle 버전을 확인해야 한다.

Fig5. build.gradle파일 찾기

Fig5처럼 프로젝트 수준의 build.gradle 파일로 들어가면 Example1 같은 부분을 볼 수 있다.

Example1. build gradle 버전 확인하기
buildscript {
...
dependencies {
classpath 'com.android.tools.build:gradle:버전'
...
}
}

Example1의 ‘버전’ 부분이 3.6이상 4.0 미만이라면 모듈 수준의 build.gradle 파일(Fig5에서 선택된 파일 바로 아래 파일)로 들어가서 Example2–1와 같이 추가해주고, 4.0 이상이라면 Example2–2와 같이 추가해주자.

Example2-1. build gradle 버전이 3.6이상 4.0미만인 경우
android {
...
viewBinding {
enabled = true
}
}
Example2-2. build gradle 버전이 4.0 이상인 경우
android {
...
buildFeatures {
viewBinding true
}
}

그리고 난 후 Sync now 버튼을 눌러 동기화해주면 View Binding을 사용할 준비가 되었다. 이제 이 모듈에 포함된 layout xml 파일은 모두 Binding 클래스가 생성된다. 만약 Binding 클래스로 만들고 싶지 않은 layout xml파일이 있다면 Example3처럼 가장 바깥의 layout에 추가해줄 수 있다.

Example3. Binding 클래스를 생성하지 않을 layout 정해주기
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>

2. kotlin 파일(.kt)이나 java 파일(.java)에서 Binding 객체를 inflate하고, Binding객체를 사용하여 View 객체에 접근할 수 있다.

Fig6. Binding 객체를 inflate하여 사용하기

1번 과정을 거쳤다면 layout xml파일 이름을 파스칼 표기법으로 나타낸 것에 Binding 을 붙인 이름으로 Binding 클래스가 생성된다. 예를 들면, Fig4에서 본 것처럼 activity_main3.xml 과 같이 스네이크 표기법으로 나타낸 layout xml파일 이름이 ActivityMain3Binding과 같이 바뀐 이름으로 바인딩 클래스가 생성된다. 이 클래스를 통해 layout xml을 inflate하면, 이 객체는 id가 있는 뷰들과 root 뷰에 대해 각각 타입이 맞는 View 객체를 프로퍼티로 갖고 있다. 따라서 boilerplate 코드 없이 binding 객체를 통해 id가 있는 View들과 root 뷰에 접근할 수 있다.

정리

(ButterKnife와 Data Binding도 Binding과 관련되지만 본 포스트에선 다루지 않았다.)

Reference

Overall part

1. [Android Developers] “View Binding” — https://developer.android.com/topic/libraries/view-binding

2. [커니의안드로이드] “번역: 코틀린 안드로이드 익스텐션의 미래” — https://www.androidhuman.com/2020-11-24-the_future_of_kotlin_android_extensions

ViewBinding part

3. [커니의안드로이드] “간편하고 안전하게 레이아웃 내 뷰를 참조하는 방법: 안드로이드 뷰 바인딩” — https://www.androidhuman.com/2020-11-25-android_view_binding

4. [투덜이의 리얼 블로그] “Android view binding” — https://tourspace.tistory.com/314

--

--

dEpayse

나뿐만 아니라 다른 사람들도 이해할 수 있도록 작성하는, 친절한 블로그를 목표로.