AndroidのDataBindingをtwo way にしたいとき
公式のドキュメントだとパッと見つけられないのでメモ
通常のDataBinding ViewModelの値を更新 → Viewも更新
TwoWayの場合 ViewModelの値を更新 → Viewも更新 Viewを更新 → ViewModelの値を更新
というように、ViewModel、View双方にObserveし合って、更新することができます。 ぐっとコードの記述量が減り、便利です。
BaseObservableを継承したViewModelを実装
public class ProfileViewModel extends BaseObservable { private int id; private String name; private boolean hasDetails; public int getId() { return id; } public String getName() { return name; } public boolean isHasDetails() { return hasDetails; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setHasDetails(boolean hasDetails) { this.hasDetails = hasDetails; } }
ViewModelクラスはJavaBeansのプロパティ設定に則って、setter/getterが getプロパティ名 setプロパティ名
なので、 booleanの場合は isプロパティ名 setプロパティ名
です。
@={viewModel.name}
通常であれば、
<EditText android:height="wrap_content" android:width="wrap_content" android:text="@{viewModel.name}"/>
とするところを、
<EditText android:height="wrap_content" android:width="wrap_content" android:text="@={viewModel.name}"/>
のように、@の後ろに=を足してあげることで、EditTextに入力したStringがviewModelのsetName(String name)の引数nameに渡されます。 しかし、このままでは、viewModelのnameが変更されたことがViewに反映されません。
<TextView android:height="wrap_content" android:width="wrap_content" android:text="@{viewModel.name}"/> <EditText android:height="wrap_content" android:width="wrap_content" android:text="@={viewModel.name}"/>
のように、nameが別のViewに使われていた場合、そちらに変更が伝わりません。 そこで、@Bindableアノテーションを使います。
@Bindable
変更を通知してもらいたいところに、@Bindableアノテーションを付けます。
@BIndable public String getName() { return name; }
@Bindableアノテーションを付けたフィールドは、BRクラスというクラスのフィールドとして定義されます。 そして、
public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); }
のように、変更されたときに、変更をnotifyPropertyChanged()メソッドによって伝えることができ、Viewに変更が伝えられます。 なお、notifyPropertyChanged(BR._all) を指定することで、@Bindableアノテーションを付けたフィールド全部に変更を伝えることができます。