Kotlinでは以前は「Kotlin Android Extensions」を使ってコードを簡略化できていましたが非推奨となりました
View Binding が「大概のケース」でfindViewByIdの後継として使えます。例外もありますが
2024.1.1
View Binding の設定
XMLレイアウトファイルからIDを読みだして、findViewById を使ってコードと結びつけるのが昔からの方法です
findViewByIdは公式に非推奨になっているわけではありませんが、安全で効率的な方法としてView Bindingを推奨しています
findViewById の不都合なことがある場合として、
- nullable
- findViewByIdの戻り値はnullableで呼び出しタイミングが悪い、あるいは間違ったidを呼び出してnullになる可能性が潜んでいる
- 型の指定
- 型安全ではないので型を指定して呼び出す必要がある
- 紐づけが面倒
- たくさんの紐づけをする場合に顕著に表れる冗長的な作業、バグの元
等があります。1つ2つであればfindViewById は簡単ですが大きなプロジェクトでは
View Binding が推奨されるでしょう。
build.gradleの設定
build.gradle ファイルに viewBinding 要素を追加し true にします。
同じ名前のファイルが2つあり、プロジェクト用(Project: xxx)とモジュール用(Module: xxx.app)で、モジュール用を使用します。
ターゲットのAPIレベルやライブラリーの情報が設定されます。
build.gradle(Module: xxx)
1 2 3 4 5 6 7 8 9 |
... android { ... buildFeatures { viewBinding = true } } ... |
あるいは、gradle.properties に以下のような記述を追加しても可能です
1 |
android.defaults.buildfeatures.viewbinding=true |
設定後に「Sync Now」を実行するのを忘れずに
また反映されるのに時間がかかることもあります
Binding Classを生成
プロジェクトのレイアウトファイル毎にViewBinding Class を作成します。
1 2 3 |
package com.example.testbutton ... import com.example.testbutton.databinding.ActivityMainBinding |
例えば、activity_main.xml の場合はactivity_mainをキャメルケースに変換して、package name とdatabindingを頭に付け、末尾に「Binding」を追加することで生成します。
[package name].databinding.[XMLレイアウトファイル名から]Binding
activity_main.xml | >> | ActivityMainBinding |
sub_layout.xml | >> | SubLayoutBinding |
main.xml | >> | MainBinding |
activity_main.xmが以下のような場合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout ... > <TextView android:id="@+id/text_view" ... /> <ImageView android:src="@drawable/image" ... /> <EditText android:id="@+id/edittext" .../> <Button android:id="@+id/button" ... /> </androidx.constraintlayout.widget.ConstraintLayout> |
Binding Class のActivityMainBindingには3つのフィールドがあります。
- text_view という名前の TextView フィールド
- edittext という名前の EditText フィールド
- button という名前の Button フィールド
bindingで以下のように参照できます
1 2 3 4 5 |
binding.textView... binding.edittext... binding.button... |
ImageViewには ID が無いので、このバインディングクラス内にそのビューへの参照は存在しません。
Binding Classには getRoot() メソッドも含まれるので、レイアウトファイルの
root viewを直接参照できます。上記のActivityMainBindingクラスでは getRoot() により
constraintlayout の root view を返します。
Activityへの実装
MainActivityの onCreate() で次の手順を実施
- Binding Classのインスタンスを生成
- Binding Classに含まれる静的 inflate() メソッドを呼び出し生成
- getRoot()を呼び出してroot viewへの参照を取得
- あるいはKotlin プロパティ構文を使用
- root view を setContentView() に渡す
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// View Binding Class のインスタンス // lateinit で宣言し初期化タイミングを onCreate() まで遅らせる private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // bindingのイニシャライズ // Binding Classに含まれる静的 inflate() メソッドを呼び出す binding = ActivityMainBinding.inflate(layoutInflater) // root view への参照を取得 val view = binding.root // view をsetContentView()にセット setContentView(view) binding.button.setOnClickListener { ... } } |
冗長なので短縮できます
1 2 |
// view をsetContentView()にセット setContentView(binding.root) |
以上で設定ができました。
References:
Migrate from Kotlin synthetics to Jetpack view binding
Kotlin Android Extensions の未来
ビュー バインディング – Android Developers
findViewById
BuildFeatures | Android Developers