RxKotlin: Login Screen
Rx is powerful because we can compose transformations. What that means is that we can have reusable, safe and more functional code that simply plugs into your code.
As an example let’s say we’re making a login screen with an email and a password…
Consider the following rules that we want for our email addresses
Length should be greater than 6
Should have a correct email pattern
Let the user know if any of the above fails
On each key stroke, verify
This is what my code should look like
emailObservable
-> lengthGreaterThanSix
-> verifyEmailPattern
-> retryIfSomethingFails
subscribe()
Simple enough, right?
Similarly for passwords, we’d want
passwordObservable
-> lengthGreaterThanSix
-> retryIfSomethingFails
subscribe()
Both fields have lengthGreaterThanSix common, so let’s create an ObservableTransformer. ObservableTransformers allows composable set of transformations that we can apply on a given observable.
Here we specify transformer’s inputStream & outStream as String. Trim the input String — filter and check if the length is greater than 6 — If not then intercept exception and throw a custom one (i.e. if previously no exception was already thrown in the chain). SingleOrError converts the Observable to a Single, so we convert it back to an Observable.
Similarly write a transformer for email pattern verification.
Here again, we trim, filter to check if the pattern matches, throw an error if it doesn’t match, and intercept to throw a custom exception instead.
Time to test these two transformations, first the character length check
Now a test for email verification, first invalid email “abcabcabc”
And for correct email “name@domain.com”
So far so good!
Connecting things with a UI
Let’s say I have this screen
For brevity, I’m gonna use RxBindings!
When I run this code, in the editText if I go beyond 6 letters, it gives me this weird exception.
onError: Sequence contains more than one element!
So what exactly is different when I use EditText onTextChange with my observables? In both cases I’m doing the same thing, right?
[Narrator: He wasn’t doing the same thing.]
Actually the difference is that the one with the editText is an infinite stream.
To actually explain it, streams will do the trick…
Observable.just("abc")
This produces the following stream
| — — — “abc” —→ (end)
RxTextView.afterTextChangeEvents(editTextEmail)
If I type in abc, it produces the following stream
| — — — “a” — “ab” — “abc” — →
Comparing the two streams, you can see that the first one produces only one item, and the second one emits three, hence the above code fails.
In order to fix this, we’d use flatMap with nested observables to handle each individual string inputs separately
Now if we type in abc, we’d have three observables on the stream, doing their own verification and error handling. In the end, it’ll just be one observable.
| —Obs(“a”)—Obs( “ab”) — Obs(“abc”)→
After doing the same for lengthGreaterThanSix and adding a debounce operator, the output would be like
Final code
That’s it for now!
Happy coding!
Some good sources for learning about Rx: