AndroidのData BindingライブラリのBinding Methodに関する記事がなかなか見つからなかったので、簡単にですがまとめてみます。
Data BindingライブラリやBinding Adapterについては公式ドキュメントなどをご参照ください。
Binding Methodとは
レイアウトファイルの属性とソースコードのメソッドを紐付ける仕組みのことです。
Data Bindingを使用していると、クリックイベントが発生したときにViewModelのメソッドを呼び出すためにandroid:onClick="@{() -> viewmodel.onClick()}"
のような実装を行う機会が多いと思います。
AndroidのData Bindingライブラリでは、レイアウトファイルに記述した属性に対応するメソッドが自動的に呼び出されるようになっています。
具体的には、以下の条件を満たすメソッドが呼び出されます。
- メソッド名: レイアウトファイルで指定した属性名に対し「set + 属性名」というメソッド名である
- 引数の型: バインディング式で指定したオブジェクトが代入可能な型である
例えば、Swiperefreshlayout
には以下のメソッドが定義されています。
void setOnRefreshListener(OnRefreshListener listener); void setRefreshing(boolean refreshing);
また、OnRefreshListener
の定義は以下の通りです。
interface OnRefreshListener { void onRefresh(); }
このとき、
- レイアウトファイルで指定した属性名が
onRefreshListener
- バインディング式で指定したオブジェクトの型がOnRefreshListener型およびその派生型
であればsetOnRefreshListener()
を、
- レイアウトファイルで指定した属性名が
refreshing
- バインディング式で指定したオブジェクトの型がboolean型(またはBoolean型)
であればsetRefreshing()
を自動的に呼び出すことが可能になります。
同様にして、クリックイベントが発生したときにViewModelのメソッドを呼び出すためには、本来であればandroid:onClickListener="@{() -> viewmodel.onClick()}"
と記述する必要があります。
これを、android:onClick="@{() -> viewmodel.onClick()}"
と記述することでsetOnClickListener()
を呼び出すことを可能にしている仕組みがBinding Methodです。
Binding Methodの宣言方法
@BindingMethods
というアノテーションの中にBinding Methodを宣言する形で記述します。
@BindingMethods
は何かしらのクラスに付与する必要があり、AOSPではBinding Adapterを宣言しているクラスに付与されているので*1、基本的にはこちらに倣うのがいいかと思います。
@BindingMethods( values = [ BindingMethod( type = View::class, attribute = "android:onClick", method = "setOnClickListener" ) ] ) object ViewBindingAdapter
この記述によって
android:onClick
にオブジェクトがセットされると- Viewクラスの
setOnClickListener()
が呼び出される
ようになります。
ただこの場合、引数がView.OnClickListener型のsetOnClick()
という関数を定義し、@BindingAdapter
アノテーションを付与することでも実現可能です。
関数の定義の仕方はいくつかありますが、object内の関数として定義する場合は@JvmStatic
アノテーションを付与する必要があります。
// トップレベル関数として @BindingAdapter fun setOnClick(view: View, listener: View.OnClickListener) { view.setOnClickListener(listener) } // 拡張関数として @BindingAdapter fun View.setOnClick(listener: View.OnClickListener) { this.setOnClickListener(listener) } // object内の関数として object ViewBindingAdapter { @JvmStatic @BindingAdapter fun View.setOnClick(listener: View.OnClickListener) { this.setOnClickListener(listener) } }
以上となります。
ここまで書いておいてあれですが、Binding Methodでやりたいことは基本的にBinding Adapterでも実現可能なため、実際にBinding Methodを使用する機会は少なそうだと感じました。笑