findViewById 함수가 Boilerplate code 이슈가 있다는 것은 대부분의 개발자들이 알고 있을 것이다.
그래서 이를 해결하기 위한 다양한 라이브러리들이 존재한다.
그 중 대표적인 두 가지에 대해서 포스팅하려고 한다.

Kotlin Android Extensions (이하 KAE)

한 줄만 추가해주면 쉽게 사용가능하다.

1. build.gradle(Module: app) 수정

...
dependencies {
    ...
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlin_version"
}

2. 사용 방법

만약 android:id = "@+id/bt_on"라는 아이디를 접근하기 위해서는,

bt_on.setText(...)
bt_on.setOnClickListener(...)

이런식으로 바로 사용 가능하다.
대신에 import문이 추가로 생성되는 것을 볼 수 있다.


🔔 [2020-10-07 추가]

안드로이드 4.1 버전에서는 더 이상 KAE를 기본 제공하지 않는다고 한다.

관련해서 태환님 블로그 글에 자세히 나와 있으니, 읽어보는게 좋겠다.






View Binding

한 줄은 아니지만 쉽게 사용 가능하다.

1. build.gradle(Module: app)

android {
    ...
    viewBinding {
        enable = true
    }
}

※ 만약 Android gradle plugin 버전이 4.0 이상이면 다음과 같이 사용해야 한다.

android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

바인딩 클래스를 생성하는 동안 레이아웃 파일을 무시하려면 다음 설정을 추가한다.

<LinearLayout
   ...
   tools:viewBindingIgnore="true">
...
</LinearLayout>

1.1 Troubleshooting

build.gradle 파일에 viewBinding 설정을 했는데, 다음과 같은 에러가 발생했다.

Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method viewBinding() for arguments [build_f2anc1ehzzonoo7anmgc2vftc$_run_closure1$_closure5@67825409] on object of type com.android.build.gradle.internal.dsl.BaseAppModuleExtension.

Gradle version이 낮아서 나타나는 문제였다. 버전을 3.6 이상으로 올려야 한다.

//build.gradle(Project:...)
buildscript {
    ext.kotlin_version = '1.3.71' // 1.3.41 -> 1.3.71 변경
    ...
    dependencies {
        classpath 'com.android.tools.build:gradle:3.6.3'  // 3.5 -> 3.6.3 변경
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // kotlin_version을 1.3.71로 바꿔야 한다고 경고 발생
    }    
}

이렇게 하면 위 에러는 해결된다.

2. 사용 방법

Data binding에서의 클래스 네이밍과 비슷하다(카멜 표기법). 예를 들어서 activity_main.xml 파일에 적용하기 위해서 생성되는 바인딩 클래스의 이름은 ActivityMainBinding이다.

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    binding.txtTitle.text("Title")
}

※ 참고로, Java에서는 다음과 같이 사용한다.

private ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ActivityMainBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    binding.txtTest.setText("View binding test");
}

Kotlin Andrid Extensions vs. View binding

먼저 공통점을 얘기해보면, 앞서 얘기한 Boilerplate code 대응이 가능하다는 점(사실 StackOverflow 글을 보면 KAE가 더 좋다고 얘기한다.) , Null safety, Type safety하다는 점이다.
그래서 개발자의 생산성을 늘릴 수 있다.

차이점을 살펴보면,

  • KAE는 kotlin만 사용 가능하지만. View binding은 Java, Kotlin 모두 사용 가능하다.
  • 레이아웃 변경에 대해 적용할 때 KAE는 즉시 synthetic extensions로 translate되어서 바로 사용할 수 있다. 그에 반해 View binding은 프로젝트를 빌드해야 한다.
  • 레이아웃을 잘 못 사용한 경우 KAE, View binding 모두 NullPointerException이 발생할 수 있다. 하지만 잘못된 Class 이름보다는 잘못된 Import 작업을 할 가능성이 더 높고, 레이아웃 파일이 Activity, Fragment, View의 이름을 따서 잘 명명된 경우에는 View binding이 더 우위를 점한다.

둘 다 나름의 특징이 있기 때문에, 무엇을 사용해야하는지는 각자 판단하면 된다.
다만, Java를 사용한다면, View binding은 기존에 사용하던 ButterKnife를 대체할 수 있겠다.
만약 Kotlin을 사용한다면, View binding과 KAE 모두 사용 가능하지만 개인적인 생각으로는 조금 더 사용하기에 간편한 KAE가 좋을 것 같다.
(근데, Data binding을 사용하는 유저들은 View binding을 좋아한다고 함)

참고

https://medium.com/kayvan-kaseb/android-jetpack-view-binding-4758c729ebe3
https://medium.com/@charlezz/view-binding-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0-df3526d909a7
https://stackoverflow.com/questions/58351239/viewbinding-vs-kotlin-android-extensions-with-synthetic-views