Given following scenario:
A View
featuring a CheckBox
and multiple EditText
s
The View
offers access to the Observables
using Jake Wharton's RxBinding like so
fun observeUsername(): InitialValueObservable<CharSequence> = RxTextView.textChanges(et_username)
for the EditText
s (there three of them, for Username, Password and Email) and
fun observeSignUpCheckBox(): InitialValueObservable<Boolean> = RxCompoundButton.checkedChanges(cb_sign_up)
for the CheckBox
The Presenter
features one method per EditText
which is as simple as
fun observeUsernameText(): Disposable {
return view.observeUsernameText()
.skipInitialValue()
.map { username -> StringUtils.isValidUsername(username.toString()) }
.subscribe({ view.setValidUsername(it) })
}
and one method for the CheckBox
:
fun observeSignUpCheckBox(): Disposable {
return view.observeSignUpCheckBox()
.subscribe({ checked ->
Timber.d("### view trigger")
})
}
all of these methods are called in the onCreate
of the Presenter
and everything worked as expected.
Now the Problem:
I added a new function in the Presenter
that validates the users input:
fun observeInputFields(): Disposable {
val email = view.observeEmailText().map { email -> StringUtils.isValidEmail(email.toString()) }
val password = view.observePasswordText().map { password -> StringUtils.isValidPassword(password.toString()) }
val signUp = view.observeSignUpCheckBox()
val username = view.observeUsernameText().map { username -> StringUtils.isValidUsername(username.toString()) }
return Observable.combineLatest(email, password, signUp, username,
Function4<Boolean, Boolean, Boolean, Boolean, Boolean> { validEmail, validPassword, signUpChecked, validUsername ->
validEmail && validPassword && (!signUpChecked || signUpChecked && validUsername)
})
.subscribe({ validForm ->
Timber.d("### form trigger")
view.enableContinue(validForm)
})
}
Whenever I change the content of an EditText
both Subscriptions
(the one for the EditText
and the combined one added in observeInputFields
) receive the event as expected.
But, if I tap on the CheckBox
only the last Subscription
receives the event depending on the order of the functions in the onCreate
.
fun onCreate() {
// here the logs only show '### form trigger'
disposables.add(observeSignUpCheckBox())
disposables.add(observeInputFields())
// ... omitted for clarity
}
or
fun onCreate() {
// here the logs only show '### view trigger'
disposables.add(observeInputFields())
disposables.add(observeSignUpCheckBox())
// ... omitted for clarity
}
I cannot figure out why this strange thing is happening only for the CheckBox
but not for the EditText
s. This is highly confusing...
Any help is greatly appreciated as I am currently stuck on this :(
Thanks!
If you check the source code of the library here and here, you will see that what you are describing is expected behaviour. For aCompoundButton
you can have only one Observable
at a time but for aTextView
multiple.
If you want to go even further you can see that here to create the Observable
you need to use the setOnCheckedChangeListener
on the CompoundButton
which replaces the possible existing listener every time.
On the other hand, for TextView
you can add multiple TextWatchers
and remove each one individually onDispose
.