淺析RxJava處理復雜表單驗證問題的方法
無論是簡單的登錄頁面,還是復雜的訂單提交頁面,表單的前端驗證(比如登錄名和密碼都符合基本要求才能點亮登錄按鈕)都是必不可少的步驟。本文展示了如何用RxJava來方便的處理表單提交前的驗證問題,例子采用了Android上的一個簡單的登錄頁面
內容提要
傳統(tǒng)的驗證方式
combineLatest操作符
用combineLatest處理表單驗證
combineLatest和zip的區(qū)別
本文中所演示的例子sample代碼位于RxAndroidDemo,參見loginActivity這個文件
傳統(tǒng)的驗證方式
這里我們用最簡單的例子來說明,如上圖,一個email輸入和一個password輸入,下方是一個登錄的按鈕。只有當email輸入框內容含有@字符,password輸入框內容大于4個,才點亮下方的按鈕。
首先你用EditText還是繼承自EditText的控件,一般來說監(jiān)聽它的內容,都是用addTextChangedListener。但是如何顯然登錄按鈕的enable與否是同時要判斷email和password的,兩個都成立才可點亮。所以我們在email的TextWatcher中除了要判斷email是否符合條件以外,還要同時判斷password是否符合條件,這樣以來就容易造成多重判斷。
試想如果你在提交一個訂單的表單,上面是十幾個輸入框,每個輸入的內容都同時符合條件才可以點亮“提交”按鈕,這是多么痛苦的事情————每一個輸入框的改變都要同時再判斷其他十幾個輸入框內容是否符合(實際上此時其他十幾個輸入框沒變化)
combineLatest操作符
combineLatest是RxJava本身提供的一個常用的操作符,它接受兩個或以上的Observable和一個FuncX閉包。當傳入的Observable中任意的一個發(fā)射數(shù)據(jù)時,combineLatest將每個Observable的最近值(Lastest)聯(lián)合起來(combine)傳給FuncX閉包進行處理。要點在于
1.combineLatest是會存儲每個Observable的最近的值
2.任意一個Observable發(fā)射新值時都會觸發(fā)操作->“combine all the Observable's lastest value together and send to Function”
用combineLatest處理表單驗證
首先我們寫上email和password的驗證方法,一個需要含有@字符,一個要求字符數(shù)超過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分別創(chuàng)建Observable,發(fā)射的值即為各自edittext的變化的內容,而call回調方法的返回值是textWatcher中afterTextChanged方法的傳入?yún)?shù):
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聯(lián)合起來進行驗證:
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就是經(jīng)過combineLastest對兩者驗證后組合的結果。
參見LoginActivity的bindView()方法
這里,即使表單非常復雜,實際上你需要擴展的話就很容易了:
1.對每個EditText封裝一個Observable
2.改寫這句話,加入新的邏輯:
return isEmailValid(email) && isPasswordValid(password);
覺得為每一個EditText封裝一個Observable要寫很多重復代碼?放心,Jake Wharton大神早已經(jīng)想到,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的區(qū)別
zip是和combineLatest有點像的一個操作符,接受的參數(shù)也是兩個或多個Observable和一個閉包。但是區(qū)別在于:
1.zip是嚴格按照順序來組合每個Observable,比如ObservableA的第一個數(shù)據(jù)和ObservableB的第一個數(shù)據(jù)組合在一起發(fā)射給FuncX來處理,兩者的第N個數(shù)據(jù)組合在一起發(fā)射給FuncX來處理,以此類推.
2.zip并不是任意一個Observable發(fā)射數(shù)據(jù)了就觸發(fā)閉包處理,而是等待每個Observable的第N個數(shù)據(jù)都發(fā)射齊全了才觸發(fā)
zip一般用于整合多方按照順序排列的數(shù)據(jù)。
以上所述是小編給大家介紹的淺析RxJava處理復雜表單驗證問題的方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關文章
Java多線程使用阻塞隊列實現(xiàn)生產者消費者模型詳解
這篇文章主要介紹了Java多線程使用阻塞隊列實現(xiàn)生產者消費者模型詳解,主要講解阻塞隊列的特性、實際開發(fā)中常用的到的生產者消費者模型,以及生產者消費者模型解耦合、削峰填谷的好處,需要的朋友可以參考下2023-07-07使用Log4j2代碼方式配置實現(xiàn)線程級動態(tài)控制
這篇文章主要介紹了使用Log4j2代碼方式配置實現(xiàn)線程級動態(tài)控制,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12