EditTextで設定された文字列を使用して、ViewModelからのLiveData Stringオブジェクトを更新するために双方向データバインディングを使用しています。
<Android.support.design.widget.TextInputEditText
Android:id="@+id/writeReviewTitle"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:text="@={viewModel.liveReviewTitle}"
/>
したがって、私の理解では、ViewModel
は、EditTextでテキストが変更されるたびにliveReviewTitle
属性が更新されます。これは、TextWatcher、またはライブラリーによって処理されているリスニングメカニズムの使用によって発生していると思います。また、テキストを更新する必要がある場合は、setter
が呼び出されると考えました。 そうではないようです!テキストが変更されると、ViewModelでさらにいくつかのことを行う必要があるため、setter
のカスタムliveReviewTitle
を実装しましたが、それは呼び出されていない(Iデバッグを試みました)。これは、ViewModel
クラスで次のように表示されます。
var liveReviewTitle: MutableLiveData<String> = MutableLiveData()
set(value) {
field = value
customLogicHere()
}
これをsetter
でデバッグしようとしましたが、呼び出されているようには見えません!ここで何が起きてるの?少し混乱します。テキストは更新され、ViewModel
に保存されます。呼び出されないのはsetter
だけです。
もちろん、決して呼び出されることはありません。新しいMutableLiveDataを設定するのではなく、MutableLiveData内に新しい文字列値を設定します(おそらくsetValue
を使用)。
ただし、MutableLiveDataではなくMediatorLiveDataを直接公開する場合は、設定されている値をインターセプトして、値を設定した後にカスタムロジックを実行できるはずです。
編集:以下は期待どおりに機能するはずです。
val liveReviewTitle: MutableLiveData<String> = MutableLiveData()
private val mediator = MediatorLiveData<String>().apply {
addSource(liveReviewTitle) { value ->
setValue(value)
customLogicHere()
}
}.also { it.observeForever { /* empty */ } }
@EpicPandaForceソリューションは適切ですが、EditText
では双方向のバインディングをより簡単な方法で取得できます。以下のように、属性afterTextChanged
をウィジェットに追加します。
_Android:afterTextChanged="@{viewModel::doLogic}"
_
次に、ViewModel
クラスにメソッドを書き込むだけです。
fun doLogic(s: Editable) { //update Livedata or do other logic }
[〜#〜]編集[〜#〜]
重要なドキュメントを見逃してしまいました note 。はるかに簡単です(そしてはるかに適切です):
_Android:text="@={viewModel.someLivedata}
_
次に、LifecycleOwner
クラスで、必要に応じてliveDataの値を毎回更新できます。もちろん、登録されたオブザーバーからの変更に対応できます。
@EpicPandaForceはあなたのセッターについて正しいです、それはMutableLiveData
自体のためであり、それが保持している値ではありません。したがって、LiveData
はval
である必要があり、var
である必要はありません。また、LifecycleOwner
バインディング。カスタムセッターの代わりに別のObserver
をLiveData
に追加して、カスタムロジックを追加できます。