I am using 2-way data binding to update a LiveData String object from my ViewModel with a string set in the EditText:
<android.support.design.widget.TextInputEditText
android:id="@+id/writeReviewTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={viewModel.liveReviewTitle}"
/>
So, from my understanding, the ViewModel
would have its liveReviewTitle
attribute updated every time the text changed in the EditText. I assume this is happening through the usage of a TextWatcher or some sort of listening mechanism that is being taken care of for me by the library. I also thought that when the text needed to be updated, it would have its setter
called. Which does not seem to be the case! When the text changes, I need to do some more stuff in my ViewModel, therefore I implemented a custom setter
for liveReviewTitle
, but it is not being called (I tried debugging).
This is how it looks like in the ViewModel
class:
var liveReviewTitle: MutableLiveData<String> = MutableLiveData()
set(value) {
field = value
customLogicHere()
}
Tried debugging this setter
but it never seems to be called! What is happening here? Feels a little confusing. The text is being updated, and it is saved in the ViewModel
, it is just the setter
that is not called.
Of course it's never called, you're not setting a new MutableLiveData, you're setting a new String value inside the MutableLiveData (possibly with setValue
).
However, you should be able to intercept the value that's being set and execute custom logic after setting the value if you expose a MediatorLiveData instead of the MutableLiveData directly.
EDIT: the following should work as expected:
val liveReviewTitle: MutableLiveData<String> = MutableLiveData()
private val mediator = MediatorLiveData<String>().apply {
addSource(liveReviewTitle) { value ->
setValue(value)
customLogicHere()
}
}.also { it.observeForever { /* empty */ } }
@EpicPandaForce is right about your setter, it's for the MutableLiveData
itself and not the value it's holding. So your LiveData
should be a val
, no need for it to be a var
, and the framework should do the right thing as long as you set a LifecycleOwner
on the binding. You could add another Observer
to your LiveData
in place of a custom setter to add your custom logic.
@EpicPandaForce solution is proper but in EditText
two way binding can be obtained in much simpler way.
Add attribute afterTextChanged
to your widget as below:
android:afterTextChanged="@{viewModel::doLogic}"
Then in your ViewModel
class just write method:
fun doLogic(s: Editable) {
//update Livedata or do other logic
}
EDIT
I have missed important documentation note. Much easier (and far more proprer) will be:
android:text="@={viewModel.someLivedata}
and then in our LifecycleOwner
class we can update value of liveData everywhe when we need, and of course we can react on changes from registered observer.