不管是简单的登陆页面,仍是复杂的订单提交页面,表单的前端验证(好比登陆名和密码都符合基本要求才能点亮登陆按钮)都是必不可少的步骤。本文展现了如何用RxJava来方便的处理表单提交前的验证问题,例子采用了Android上的一个简单的登陆页面前端
本文中所演示的例子sample代码位于RxAndroidDemo,参见loginActivity这个文件java
这里咱们用最简单的例子来讲明,如上图,一个email输入和一个password输入,下方是一个登陆的按钮。只有当email输入框内容含有@字符,password输入框内容大于4个,才点亮下方的按钮。git
首先你用EditText仍是继承自EditText的控件,通常来讲监听它的内容,都是用addTextChangedListener。可是如何显然登陆按钮的enable与否是同时要判断email和password的,两个都成立才可点亮。因此咱们在email的TextWatcher中除了要判断email是否符合条件之外,还要同时判断password是否符合条件,这样以来就容易形成多重判断。
试想若是你在提交一个订单的表单,上面是十几个输入框,每一个输入的内容都同时符合条件才能够点亮“提交”按钮,这是多么痛苦的事情————每个输入框的改变都要同时再判断其余十几个输入框内容是否符合(实际上此时其余十几个输入框没变化)github
combineLatest是RxJava自己提供的一个经常使用的操做符,它接受两个或以上的Observable和一个FuncX闭包。当传入的Observable中任意的一个发射数据时,combineLatest将每一个Observable的最近值(Lastest)联合起来(combine)传给FuncX闭包进行处理。要点在于闭包
首先咱们写上email和password的验证方法,一个须要含有@字符,一个要求字符数超过4个:app
private boolean isEmailValid(String email) { //TODO: Replace this with your own logic return email.contains("@"); } private boolean isPasswordValid(String password) { //TODO: Replace this with your own logic return password.length() > 4; }
随后,咱们针对email和password分别建立Observable,发射的值即为各自edittext的变化的内容,而call回调方法的返回值是textWatcher中afterTextChanged方法的传入参数:ide
Observable<String> ObservableEmail = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(final Subscriber<? super String> subscriber) { mEmailView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { subscriber.onNext(s.toString()); } }); } }); Observable<String> ObservablePassword = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(final Subscriber<? super String> subscriber) { mPasswordView.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { subscriber.onNext(s.toString()); } }); } });
最后,用combineLastest将ObservableEmail和ObservablePassword联合起来进行验证:this
Observable.combineLatest(ObservableEmail, ObservablePassword, new Func2<String, String, Boolean>() { @Override public Boolean call(String email, String password) { return isEmailValid(email) && isPasswordValid(password); } }).subscribe(new Subscriber<Boolean>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Boolean verify) { if (verify) { mEmailSignInButton.setEnabled(true); } else { mEmailSignInButton.setEnabled(false); } } });
onNext中的verify就是通过combineLastest对二者验证后组合的结果。code
参见LoginActivity的bindView()方法继承
这里,即便表单很是复杂,实际上你须要扩展的话就很容易了:
return isEmailValid(email) && isPasswordValid(password);
以为为每个EditText封装一个Observable要写不少重复代码?放心,Jake Wharton大神早已经想到,RxBinding中的RxTextView就能够解决这个问题:
Observable<CharSequence> ObservableEmail = RxTextView.textChanges(mEmailView); Observable<CharSequence> ObservablePassword = RxTextView.textChanges(mPasswordView); Observable.combineLatest(ObservableEmail, ObservablePassword, new Func2<CharSequence, CharSequence, Boolean>() { @Override public Boolean call(CharSequence email, CharSequence password) { return isEmailValid(email.toString()) && isPasswordValid(password.toString()); } }).subscribe(new Subscriber<Boolean>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Boolean verify) { if (verify) { mEmailSignInButton.setEnabled(true); } else { mEmailSignInButton.setEnabled(false); } } });
参见LoginActivity的bindViewByRxBinding()方法
zip是和combineLatest有点像的一个操做符,接受的参数也是两个或多个Observable和一个闭包。可是区别在于:
zip通常用于整合多方按照顺序排列的数据。