無論是簡單的登錄頁面,還是復雜的訂單提交頁面,表單的前端驗證(比如登錄名和密碼都符合基本要求才能點亮登錄按鈕)都是必不可少的步驟。本文展示了如何用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個:
1
2
3
4
5
6
7
8
|
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方法的傳入參數:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
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聯合起來進行驗證:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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.改寫這句話,加入新的邏輯:
1
|
return isEmailValid(email) && isPasswordValid(password); |
覺得為每一個EditText封裝一個Observable要寫很多重復代碼?放心,Jake Wharton大神早已經想到,RxBinding中的RxTextView就可以解決這個問題:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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處理復雜表單驗證問題的方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!