Android用RxJava combineLatest操作符处理复杂表单验证问题

来源:互联网 发布:阿里云香港机房 编辑:程序博客网 时间:2024/06/13 15:27

传统的验证方式

这里我们用最简单的例子来说明,如上图,一个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对两者验证后组合的结果。

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

  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);        }    }});

combineLatest和zip的区别

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

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

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

这里写图片描述

原文:http://www.cnblogs.com/soaringEveryday/p/5578921.html

0 0
原创粉丝点击