Kotlin 1.4.20-M2でDeprecatedとなったKotlin Android Extensionsを弔う

表題の通り`Kotlin 1.4.20-M2`でKotlin Android ExtensionsがDeprecatedとなりました、個人的には好きな技術だったので弔いがてら記事にしたいと思います。

2020/11/25追記
オフィシャルからもお言葉がありました。
https://android-developers-jp.googleblog.com/2020/11/the-future-of-kotlin-android-extensions.html

## 概要
Kotlin Android Extensions[1]はKotlin用のView参照機構で、`findViewById`によるViewの参照の問題を解決するために導入された。手軽に導入できシンタックスもシンプルなので採用しているプロジェクトも多いように思うが、後述するいくつかの問題によりAndroid公式からはBest Practiceとはされていなかった。

このような背景からView参照機構として長らく`findViewById`,`ButterKnife`,`Kotlin Android Extensions`といった技術が存在する状況が続いてたが（`DataBinding`は除く）、2019年のGoogle I/OにてViewBinding[2]が発表されView参照機構のBest Practice問題は一様の収束に至った。

これを受けて昨日リリースされた`Kotlin 1.4.20-M2`[3]では遂に`KT-42121 Deprecate Kotlin Android Extensions compiler plugin` となり、今後多くのAndroidプロジェクトのView参照機構はViewBindingへmigrateされていくことになると思う。


## Why kotlinx synthetic is no longer a recommended practice
redditにてなぜkotlinx syntheticはrecommended practiceではないのか、というスレッドで議論がされておりその中に以下の回答がされている。[4]

> We’ve been shifting away from them (e.g. we don’t teach them in the Udacity course) because they expose a global namespace of ids that’s unrelated to the layout that’s actually inflated with no checks against invalid lookups, are Kotlin only, and don't expose nullability when views are only present in some configuration. All together, these issues cause the API to increase number of crashes for Android apps.

これによるとKotlin Android Extensionsの問題として`global namespace of ids`, `Kotlin only`, `don't expose nullability`があげられている。

#### global namespace of ids
これはKotlin Android Extensionsを使ったことがある人なら一度は経験したことはあると思う。Kotlin Android Extensionsのlayout id定義はグローバルに存在しlayout idのViewをimportして参照したとしてもコンパイルエラーで気がつくことができない。

#### Kotlin only
当然Kotlinでしか利用できないためJavaで記述されたActivityなどでは引き続きButterKnifeやfindViewByIdを使う必要があった。

#### don't expose nullability
when views are only present in some configuration、例えば以下のようにportrait,landscapeで異なるlayoutを定義していた場合を考えると

activity_kotlin_android_extensions.xml

```xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".KotlinAndroidExtensionsActivity">

</FrameLayout>
```

land/activity_kotlin_android_extensions.xml


```xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".KotlinAndroidExtensionsActivity">

    <TextView
        android:id="@+id/label_kotlin_android_extensions_land"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>
```

この状態で例えばActivityでTextViewを参照しようとするとwarningが発生するもののクラッシュするまで問題に気づくことはできない。

```kotlin
...
label_kotlin_android_extensions.text = "bar" // warning: The resource is missing in some of layout versions
...
```

一方ViewBindingを利用して参照する場合Viewはnullableとなるためコンパイルエラーとなる。

```kotlin
...
binding.labelKotlinAndroidExtensions.text = "bar" // only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type TextView?
...
```

## 終わりに
以上Kotlin Android ExtensionsがDeprecatedになった経緯を眺めた。ViewBindingは`Android Studio 3.6 Canary 11`以降から使用可能でActivity/Fragment単位で段階的な導入もできる。自分が携わっているプロダクトでは主にDataBindingを使用しているため移行する必要はあまりなさそうだが、一部ButterKnifeによる記述が残っているのでそのあたりから移行を進めていこうと思う。

※ proandroiddevのほうでもKotlin Android ExtensionsのDeprecatedの件に触れていた[5]


## 参考
[1] [https://developer.android.com/kotlin/ktx:title]

[2] [https://developer.android.com/topic/libraries/view-binding?hl=ja:title]

[3] [https://github.com/JetBrains/kotlin/releases/tag/v1.4.20-M2:title]

[4] [https://www.reddit.com/r/androiddev/comments/ala9p2/why_kotlinx_synthetic_is_no_longer_a_recommended/:title]

[5] [https://proandroiddev.com/migrating-the-deprecated-kotlin-android-extensions-compiler-plugin-to-viewbinding-d234c691dec7:title]