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

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

生成されたバインディング クラスは、レイアウト変数をレイアウト内のビューに関連付けます。バインディング クラスの名前とパッケージはカスタマイズ可能です。生成されたすべてのバインディング クラスの継承元は、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);

    

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 はデータ バインディングと同様に必須ではありません。ただし、コードからビューへのアクセスが必要なインスタンスもあります。

変数

データ バインディング ライブラリは、レイアウトで宣言された変数ごとにアクセサ メソッドを生成します。たとえば、次のレイアウトでは、userimagenote の各変数用のセッター メソッドとゲッター メソッドがバインディング クラスに生成されます。

<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 型のため、生成されたバインディング クラス内で ViewStubViewStubProxy オブジェクトに置き換えられます。その結果、存在する場合は 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 サフィックスを付加します)。クラスはモジュール パッケージの databinding パッケージに配置されます。たとえば、レイアウトファイル contact_item.xmlContactItemBinding クラスを生成します。モジュール パッケージが 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>
    

参考情報

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

サンプル

コードラボ

ブログ投稿