データ バインディング ライブラリは、レイアウトの変数とビューにアクセスするために使用されるバインディング クラスを生成します。このページでは、バインディング クラスの生成方法とカスタマイズ方法を説明します。
生成されたバインディング クラスは、レイアウト変数をレイアウト内のビューに関連付けます。バインディング クラスの名前とパッケージはカスタマイズ可能です。生成されたすべてのバインディング クラスの継承元は、ViewDataBinding
クラスです。
バインディング クラスはレイアウト ファイルごとに生成されます。デフォルトのクラス名は、ベースとなるレイアウト ファイルの名前がパスカルケースに変換され、Binding サフィックスが付加されたものです。上記のレイアウト ファイルの名前は activity_main.xml
であるため、生成されるクラスの名前は ActivityMainBinding
になります。このクラスは、レイアウト プロパティ(user
変数など)からレイアウトのビューへのバインディングをすべて保持します。また、バインディング式で使用する値の割り当て方法を認識しています。
バインディング オブジェクトを作成する
バインディング オブジェクトは、レイアウトをインフレートした直後に作成して、ビュー階層がビューにバインドされる前にレイアウト内の式によって変更されないようにします。オブジェクトをレイアウトにバインドする最も一般的な方法は、バインディング クラスの静的メソッドを使用することです。次の例に示すように、バインディング クラスの inflate()
メソッドを使用することで、ビュー階層をインフレートしてオブジェクトをバインドできます。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: MyLayoutBinding = MyLayoutBinding.inflate(layoutInflater) setContentView(binding.root) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater()); setContentView(binding.root); }
次の例に示すように、inflate()
メソッドには LayoutInflater
オブジェクトに加えて ViewGroup
オブジェクトを受け取るバージョンもあります。
Kotlin
val binding: MyLayoutBinding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false)
Java
MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false);
別のメカニズムを使用してレイアウトがインフレートされた場合、次のように個別にバインドできます。
Kotlin
val binding: MyLayoutBinding = MyLayoutBinding.bind(viewRoot)
Java
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
バインドタイプが事前にわからない場合もあります。その場合は、次のコード スニペットに示すように、DataBindingUtil
クラスを使用してバインディングを作成できます。
Kotlin
val viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent) val binding: ViewDataBinding? = DataBindingUtil.bind(viewRoot)
Java
View viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent); ViewDataBinding binding = DataBindingUtil.bind(viewRoot);
Fragment
、ListView
、RecyclerView
アダプター内でデータ バインディング アイテムを使用している場合は、次のコード例に示すように、バインディング クラスまたは DataBindingUtil
クラスの inflate()
メソッドを使用することをおすすめします。
Kotlin
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) // or val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
Java
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false); // or ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
ID 付きのビュー
データ バインディング ライブラリはレイアウト内で、ID 付きのビューごとにバインディング クラスに固定フィールドを作成します。たとえば、データ バインディング ライブラリは、次のレイアウトから TextView
型の firstName
フィールドと lastName
フィールドを作成します。
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:id="@+id/firstName"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"
android:id="@+id/lastName"/>
</LinearLayout>
</layout>
ライブラリは、単一のパスでビュー階層から ID 付きのビューを抽出します。このメカニズムは、レイアウト内のビューごとに findViewById()
メソッドを呼び出すよりも短時間で実行できます。
ID はデータ バインディングと同様に必須ではありません。ただし、コードからビューへのアクセスが必要なインスタンスもあります。
変数
データ バインディング ライブラリは、レイアウトで宣言された変数ごとにアクセサ メソッドを生成します。たとえば、次のレイアウトでは、user
、image
、note
の各変数用のセッター メソッドとゲッター メソッドがバインディング クラスに生成されます。
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
ViewStub
ViewStub
オブジェクトは通常のビューとは異なり、最初は非表示のビューとして設定されます。このオブジェクトは、表示されるか、インフレートするように明示的に指示されると、別のレイアウトをインフレートすることによってレイアウト内で自身を置き換えます。
ViewStub
は実質的にビュー階層に表示されないため、バインディング オブジェクトのビューも非表示にして、ガベージ コレクションで回収できるようにする必要があります。ビューは final 型のため、生成されたバインディング クラス内で ViewStub
が ViewStubProxy
オブジェクトに置き換えられます。その結果、存在する場合は ViewStub
にアクセスできるようになり、ViewStub
がインフレートされている場合は、インフレートされたビュー階層にもアクセスできるようになります。
別のレイアウトをインフレートする場合は、新しいレイアウト用のバインディングを設定する必要があります。
そのため、ViewStubProxy
で ViewStub
OnInflateListener
をリッスンし、必要に応じてバインディングを設定する必要があります。特定の時点で存在できるリスナーは 1 つのみであるため、ViewStubProxy
ではバインディングの設定後に呼び出される OnInflateListener
を設定できます。
即時バインディング
変数または監視可能なオブジェクトを変更する場合は、次のフレームの前に変更するようにバインディングのスケジュールが設定されます。ただし、バインディングをすぐに実行する必要がある場合もあります。強制的に実行するには、executePendingBindings()
メソッドを使用します。
高度なバインディング
動的変数
特定のバインディング クラスを識別できない場合もあります。たとえば、任意のレイアウトに対して動作する RecyclerView.Adapter
は、特定のバインディング クラスを認識しません。さらに、onBindViewHolder()
メソッドの呼び出し中にバインディングの値を割り当てる必要もあります。
次の例では、RecyclerView
がバインドするすべてのレイアウトに item
変数があります。BindingHolder
オブジェクトには、ViewDataBinding
基本クラスを返す getBinding()
メソッドがあります。
Kotlin
override fun onBindViewHolder(holder: BindingHolder, position: Int) { item: T = items.get(position) holder.binding.setVariable(BR.item, item); holder.binding.executePendingBindings(); }
Java
public void onBindViewHolder(BindingHolder holder, int position) { final T item = items.get(position); holder.getBinding().setVariable(BR.item, item); holder.getBinding().executePendingBindings(); }
バックグラウンド スレッド
データモデルは、コレクションでなければ、バックグラウンド スレッドで変更できます。データ バインディングでは、評価中に各変数およびフィールドをローカライズすることによって同時実行に関する問題が発生しないようにしています。
カスタムのバインディング クラスの名前
デフォルトでは、バインディング クラスの名前はレイアウト ファイルの名前に基づいて付けられます(レイアウト ファイル名の先頭の文字を大文字にし、アンダースコア(_)を削除してその次の文字を大文字にし、最後に Binding サフィックスを付加します)。クラスはモジュール パッケージの databinding
パッケージに配置されます。たとえば、レイアウトファイル contact_item.xml
は ContactItemBinding
クラスを生成します。モジュール パッケージが com.example.my.app
の場合、バインディング クラスは com.example.my.app.databinding
パッケージに配置されます。
data
要素の class
属性を調整することで、バインディング クラスの名前を変更する、または別のパッケージに配置することができます。たとえば次のレイアウトは、ContactItem
バインディング クラスを現在のモジュールの databinding
パッケージ内に生成します。
<data class="ContactItem">
…
</data>
ピリオドを使用してクラス名にプレフィックスを付加すると、バインディング クラスを別のパッケージ内に生成できます。次の例では、バインディング クラスをモジュール パッケージ内に生成します。
<data class=".ContactItem">
…
</data>
また、バインディング クラスを生成する場合、完全なパッケージ名を使用できます。次の例では、ContactItem
バインディング クラスを com.example
パッケージ内に生成します。
<data class="com.example.ContactItem">
…
</data>
参考情報
データ バインディングの詳細については、以下の参考情報をご確認ください。