sky’s 雑記

主にAndroidとサーバーサイドの技術について記事を書きます

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

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

概要

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 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 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が発生するもののクラッシュするまで問題に気づくことはできない。

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

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

...
binding.labelKotlinAndroidExtensions.text // 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] Android KTX  |  Android Developers

[2] ビュー バインディング  |  Android デベロッパー  |  Android Developers

[3] Release Kotlin 1.4.20-M2 · JetBrains/kotlin · GitHub

[4] Why kotlinx synthetic is no longer a recommended practice : androiddev

[5] Migrating the deprecated Kotlin Android Extensions compiler plugin to ViewBinding | by Ahmad El-Melegy | Oct, 2020 | ProAndroidDev