🍣

MutableLiveData は双方向データバインディングにも使える

2020/10/23に公開

データバインディングを利用して EditText に入力した内容を ViewModel に通知する処理を実装していました。

<EditText
    android:id="@+id/form_user_name_edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@{viewmodel.userName}" />
FormViewModel.kt
class FormViewModel : ViewModel() {
    var userName = ObservableField<String>()
}

上記の実装だと、FormViewModelからuserNameを変更すると View に反映されますが、逆に画面からテキストを入力してもFormViewModeluserNameに反映されません。
つまり、ViewModel -> View は対応しているが、View -> ViewModel には対応していません。

双方向データバインディング

上記の問題を解決するためには、「双方向データバインディング」にする必要があります。
名前の通り、ViewModel -> View だけでなく、View -> ViewModel にも対応するための仕組みです。

対応方法

それぞれ以下のように変更します。

<EditText
    android:id="@+id/form_user_name_edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={viewmodel.userName}" />

xml の方は@{の間に=を追加するだけです。

FormViewModel.kt
class FormViewModel : ViewModel() {
    val userName = MutableLiveData<String>()
}

ViewModel の方はFormViewModeluserNameMutableLiveData<String>に変更するだけです。
また、MutableLiveData を使わない、従来型の方法(公式サイト記載)もあります。

FormViewModel.kt
import com.example.simplemvvmapp.BR

class FormViewModel : BaseObservable() {
    @Bindable
    var userName: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.userName)
        }
}

ですが MutableLiveData を使う方が簡単に書けますし、ライフサイクルにも考慮してくれるので、MutableLiveData を使うことをお勧めします。

まとめ

MutableLiveData は双方向データバインディングにも使えるということがわかりました。
普通にデータバインディング以外にも使えるのでもっと積極的に使っていきたいです。

参考 URL

Discussion