生成されたバインディング クラス

データ バインディング ライブラリは、レイアウトの変数とビューへのアクセスに使用できるバインディング クラスを生成します。このドキュメントでは、生成されたバインディング クラスを作成してカスタマイズする方法を説明します。

生成されたバインディング クラスにより、レイアウト変数がレイアウト内のビューとリンクされます。バインディングの名前とパッケージはカスタマイズできます。生成されるすべてのバインディング クラスは ViewDataBinding クラスを継承します。

バインディング クラスはレイアウト ファイルごとに生成されます。デフォルトでは、クラス名はパスカルケースに変換されたレイアウト ファイルの名前に Binding 接尾辞が付加されたものになります。たとえば、レイアウト ファイル名が activity_main.xml の場合、生成されるクラスは ActivityMainBinding になります。このクラスは、レイアウト プロパティからレイアウトのビューへのすべてのバインディングを保持し、バインディング式に値を割り当てる方法を認識します。

バインディング オブジェクトを作成する

バインディング オブジェクトは、レイアウトをインフレートした直後に作成され、レイアウト内の式を使用してビュー階層が変更される前にビュー階層が変更されることがないようにします。オブジェクトをレイアウトにバインドする最も一般的な方法は、バインディング クラスで静的メソッドを使用することです。次の例に示すように、バインディング クラスの 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);

FragmentListViewRecyclerView アダプター内でデータ バインディング アイテムを使用する場合は、次のコードサンプルに示すように、バインディング クラスまたは 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 はビュー階層に表示されなくなるため、バインディング オブジェクトのビューも非表示にして、ガベージ コレクションで要求できるようにする必要があります。ビューは最終ビューであるため、ViewStubProxy オブジェクトが、生成されたバインディング クラスの ViewStub の代わりになり、ViewStub が存在する場合はそれにアクセスでき、ViewStub がインフレートされるときはインフレートされたビュー階層にアクセスできます。

別のレイアウトをインフレートする場合は、新しいレイアウトのバインディングを設定する必要があります。したがって、ViewStubProxyViewStub 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 が付加されます。たとえば、レイアウト ファイル contact_item.xmlContactItemBinding クラスを生成します。クラスは、モジュール パッケージの下の databinding パッケージに配置されます。たとえば、モジュール パッケージが com.example.my.app の場合、バインディング クラスは com.example.my.app.databinding パッケージに配置されます。

data 要素の class 属性を調整することで、バインディング クラスの名前を変更したり、別のパッケージに配置したりできます。たとえば次のレイアウトでは、現在のモジュールの databinding パッケージに ContactItem バインディング クラスが生成されます。

<data class="ContactItem">
    ...
</data>

クラス名の前にピリオドを付けると、別のパッケージにバインディング クラスを生成できます。次の例では、モジュール パッケージ内にバインディング クラスを生成します。

<data class=".ContactItem">
    ...
</data>

バインディング クラスを生成する完全なパッケージ名を使用することもできます。次の例では、com.example パッケージに ContactItem バインディング クラスを作成します。

<data class="com.example.ContactItem">
    ...
</data>

参考情報

データ バインディングの詳細については、以下の参考情報をご覧ください。