ViewModelを直接バインディング
前回、イベント処理を記述したクラスをバインディングオブジェクトにセットすることで、データバインディングを利用する方法を紹介しました。実は、ViewModelを直接バインドすることもできます。今回は、ViewModelを直接バインドする方法から始めていきます。
サンプルデータは、GitHubから参照できます。
縦の長さと横の長さを別々に生成するサンプル
前回のサンプルでは、ボタンはひとつのみであり、そのボタンをタップすることで、縦の長さと横の長さの両方が同時に生成される仕組みとなっていました。今回のサンプルは、これを別々にし、図1の画面とします。
それぞれのボタンをタップすることで、縦の長さ、横の長さがそれぞれ別々に生成されます。その場合、前回のように、それぞれのボタン用のイベント処理メソッドを、前回作成したMainHandlersのようなイベント処理クラスに定義し、そのメソッドをonClick属性に設定してもかまいません。
ボタンタップイベントにViewModelのメソッドを設定
一方で、そのメソッドの処理内容というのは、結局はViewModel内のメソッドの実行となることが多々あります。そこで、ViewModelをバインディングオブジェクトに直接バインドし、そのメソッドを設定するようにします。
例えば、縦の長さを再生成するメソッドとしてgenerateNewHeight()、同じく横の長さのgenerateNewWidth()がMainViewModelに定義されているとして、それらのメソッドをバインドするレイアウトxml上のコードは、リスト1のようになります。
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" …> <data> <variable name="mainViewModel" type="com.….MainViewModel"/> (1) </data> <androidx.constraintlayout.widget.ConstraintLayout …> : <TextView android:id="@+id/tvHeight" : android:text="@{mainViewModel.rectangle.heightStr}"/> (2) : <Button android:id="@+id/btnGenerateHeight" : android:onClick="@{(view) -> mainViewModel.generateNewHeight()}"/> (3) <Button android:id="@+id/btnGenerateWidth" : android:onClick="@{(view) -> mainViewModel.generateNewWidth()}"/> (4) </androidx.constraintlayout.widget.ConstraintLayout> </layout>
リスト1の(1)のように、variableタグのtype属性値として、単にMainViewModelを指定するだけです。変数名は、mainViewModelとしています。そして、このmainViewModelのメソッドを、onClickイベントとして設定しているのが、(3)と(4)です。
前回のイベント処理メソッドの登録構文の通り、ラムダ式を利用します。(3)では縦の長さの再生成メソッドであるgenerateNewHeight()を、(4)では横の長さのgenerateNewWidth()を登録しています。これだけで、ViewModel内のメソッドを直接実行できるようになります。
また、このMainViewModelのフィールドとしてRectangleオブジェクトを保持し、そのゲッタを用意しておくだけで、(2)のように、Rectangle内の各データには、.(ドット)を繋ぐだけでアクセスできるようになります。