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