にんにんにん

エンジニアな日々を書いていきます

AndroidのDataBindingをtwo way にしたいとき

公式のドキュメントだとパッと見つけられないのでメモ

developer.android.com

通常の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アノテーションを付けたフィールド全部に変更を伝えることができます。