用RxJava处理复杂表单验证问题

无论是简单的登录页面,还是复杂的订单提交页面,表单的前端验证(比如登录名和密码都符合基本要求才能点亮登录按钮)都是必不可少的步骤。本文展示了如何用RxJava来方便的处理表单提交前的验证问题,例子采用了Android上的一个简单的登录页面

内容提要

  • 传统的验证方式
  • combineLatest操作符
  • 用combineLatest处理表单验证
  • combineLatest和zip的区别

本文中所演示的例子sample代码位于RxAndroidDemo,参见loginActivity这个文件

传统的验证方式

这里我们用最简单的例子来说明,如上图,一个email输入和一个password输入,下方是一个登录的按钮。只有当email输入框内容含有@字符,password输入框内容大于4个,才点亮下方的按钮。

首先你用EditText还是继承自EditText的控件,一般来说监听它的内容,都是用addTextChangedListener。但是如何显然登录按钮的enable与否是同时要判断email和password的,两个都成立才可点亮。所以我们在email的TextWatcher中除了要判断email是否符合条件以外,还要同时判断password是否符合条件,这样以来就容易造成多重判断。

试想如果你在提交一个订单的表单,上面是十几个输入框,每个输入的内容都同时符合条件才可以点亮“提交”按钮,这是多么痛苦的事情————每一个输入框的改变都要同时再判断其他十几个输入框内容是否符合(实际上此时其他十几个输入框没变化)

combineLatest操作符

combineLatest是RxJava本身提供的一个常用的操作符,它接受两个或以上的Observable和一个FuncX闭包。当传入的Observable中任意的一个发射数据时,combineLatest将每个Observable的最近值(Lastest)联合起来(combine)传给FuncX闭包进行处理。要点在于

  1. combineLatest是会存储每个Observable的最近的值的
  2. 任意一个Observable发射新值时都会触发操作->“combine all the Observable's lastest value together and send to Function”

用combineLatest处理表单验证

首先我们写上email和password的验证方法,一个需要含有@字符,一个要求字符数超过4个:

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方法的传入参数:

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联合起来进行验证:

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对两者验证后组合的结果。

参见LoginActivity的bindView()方法

这里,即使表单非常复杂,实际上你需要扩展的话就很容易了:

  1. 对每个EditText封装一个Observable
  2. 改写这句话,加入新的逻辑:
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()方法

combineLatest和zip的区别

zip是和combineLatest有点像的一个操作符,接受的参数也是两个或多个Observable和一个闭包。但是区别在于:

  1. zip是严格按照顺序来组合每个Observable,比如ObservableA的第一个数据和ObservableB的第一个数据组合在一起发射给FuncX来处理,两者的第N个数据组合在一起发射给FuncX来处理,以此类推
  2. zip并不是任意一个Observable发射数据了就触发闭包处理,而是等待每个Observable的第N个数据都发射齐全了才触发

zip一般用于整合多方按照顺序排列的数据。

用RxJava处理复杂表单验证问题的更多相关文章

  1. jQuery学习之路(8)- 表单验证插件-Validation

    ▓▓▓▓▓▓ 大致介绍 jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的验证方法,包括 ...

  2. 玩转spring boot——AOP与表单验证

    AOP在大多数的情况下的应用场景是:日志和验证.至于AOP的理论知识我就不做赘述.而AOP的通知类型有好几种,今天的例子我只选一个有代表意义的“环绕通知”来演示. 一.AOP入门 修改“pom.xml ...

  3. form表单验证-Javascript

    Form表单验证: js基础考试内容,form表单验证,正则表达式,blur事件,自动获取数组,以及css布局样式,动态清除等.完整代码如下: <!DOCTYPE html PUBLIC &qu ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(33)-MVC 表单验证

    系列目录 注:本节阅读需要有MVC 自定义验证的基础,否则比较吃力 一直以来表单的验证都是不可或缺的,微软的东西还是做得比较人性化的,从webform到MVC,都做到了双向验证 单单的用js实现的前端 ...

  5. 实现跨浏览器html5表单验证

    div:nth-of-type(odd){ float: left; clear: left; } .origin-effect > div:nth-of-type(even){ float: ...

  6. jQuery Validate 表单验证 — 用户注册简单应用

    相信很多coder在表单验证这块都是自己写验证规则的,今天我们用jQuery Validate这款前端验证利器来写一个简单的应用. 可以先把我写的这个小demo运行试下,先睹为快.猛戳链接--> ...

  7. jquery validate表单验证插件-推荐

    1 表单验证的准备工作 在开启长篇大论之前,首先将表单验证的效果展示给大家.     1.点击表单项,显示帮助提示 2.鼠标离开表单项时,开始校验元素  3.鼠标离开后的正确.错误提示及鼠标移入时的帮 ...

  8. 表单验证插件之jquery.validate.js

    提到表单验证的插件,第一个想到的就是jquery.validate.js,所以小生想在这里稍微详细地说一下这款插件的具体使用方法,便于理解,我直接附上整段demo的代码(没怎么调样式,主要是看js): ...

  9. 走进AngularJs 表单及表单验证

    年底了越来越懒散,AngularJs的学习落了一段时间,博客最近也没更新.惭愧~前段时间有试了一下用yeoman构建Angular项目,感觉学的差不多了想做个项目练练手,谁知遇到了一系列问题.yeom ...

随机推荐

  1. SQLServer:删除log文件和清空日志的方法

    数据库的性能是DBA都需要重点关注的,日志文件的增多严重影响数据库的性能,本文将为您介绍SQL Server删除日志文件的方法,供您参考,希望对您有所帮助. 数据库在使用过程中会使日志文件不断增加,使 ...

  2. 【hadoop】——HDFS解压缩实现

    转载请注明出处:http://www.cnblogs.com/zhengrunjian/p/4527220.html 所有源码在github上,https://github.com/lastsweet ...

  3. ORA-01858: 在要求输入数字处找到非数字字符

    数据库   date  字段问题  insert into  WK_RE_LE  (DACL_FILE_ID,DACL_GROUP_ID,BDCDYH,DACL_LENGTH,ISVALID,DACL ...

  4. 大数据挖掘: FPGrowth初识--进行商品关联规则挖掘

    @(hadoop)[Spark, MLlib, 数据挖掘, 关联规则, 算法] [TOC] 〇.简介 经典的关联规则挖掘算法包括Apriori算法和FP-growth算法.Apriori算法多次扫描交 ...

  5. 设置输入域(input/textarea)中文本光标的位置

    以前记录了一篇 将光标定位于输入框最右侧的实现方式 ,实现光标定位在文本的最末.这种需求往往在修改现有的文本.有时可能还需要把光标定位在首位,或者中间某个位置,这就需要实现一个更通用的方法. 这个方法 ...

  6. Docker+OpenvSwitch搭建VxLAN实验环境

    一.概述                                                    1.环境:我这里是2台linux机器(host1和host2),发行版是kali2.0, ...

  7. [转] Finding the Best Programmer's Font

    原文 Finding the Best Programmer's Font

  8. jquery back to top 页面底部的返回顶部按钮

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 基于Bootstrap的DropDownList的JQuery组件的完善版

    在前文 创建基于Bootstrap的下拉菜单的DropDownList的JQuery插件 中,实现了DropDownList的JQuery组件,但是留有遗憾.就是当下拉菜单出现滚动条的时候,滚动条会覆 ...

  10. cuda并行计算的几种模式

    #include "cuda_runtime.h" #include "device_launch_parameters.h" #include <std ...