一、前言
2.1 應用背景
在平時的應用中,我們經常會讓使用者輸入一些資訊,最常見的莫過於註冊或者登入介面中,讓使用者輸入使用者名稱或者密碼,但是我們經常會對使用者名稱或者密碼有一定的要求,只有當它們同時滿足要求時,才允許使用者進行下一步的操作。
這個需求就涉及到一種模型,即在多個地方監聽變化,但是在一個地方進行統一驗證,如果驗證成功,那麼允許使用者進行下一步的操作,否則提示使用者輸入不正確。
通過這個例子,大家將學習到combineLatest
操作符的用法。
2.2 示例
在下面這個示例中,包含了兩個輸入框,分別對應使用者名稱和密碼,它們的長度要求分別為2~8
和4~16
,如果兩者都正確,那麼登入按鈕的文案變為“登入”,否則顯示“使用者名稱或密碼無效”。
public class CombineLatestActivity extends AppCompatActivity {
private EditText mEtName;
private EditText mEtPassword;
private Button mBtLogin;
private PublishSubject<String> mNameSubject;
private PublishSubject<String> mPasswordSubject;
private CompositeDisposable mCompositeDisposable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_combine_latest);
mEtName = (EditText) findViewById(R.id.et_name);
mEtPassword = (EditText) findViewById(R.id.et_password);
mBtLogin = (Button) findViewById(R.id.bt_login);
mNameSubject = PublishSubject.create();
mPasswordSubject = PublishSubject.create();
mEtName.addTextChangedListener(new EditTextMonitor(mNameSubject));
mEtPassword.addTextChangedListener(new EditTextMonitor(mPasswordSubject));
Observable<Boolean> observable = Observable.combineLatest(mNameSubject, mPasswordSubject, new BiFunction<String, String, Boolean>() {
@Override
public Boolean apply(String name, String password) throws Exception {
int nameLen = name.length();
int passwordLen = password.length();
return nameLen >= 2 && nameLen <= 8 && passwordLen >= 4 && passwordLen <= 16;
}
});
DisposableObserver<Boolean> disposable = new DisposableObserver<Boolean>() {
@Override
public void onNext(Boolean value) {
mBtLogin.setText(value ? "登入" : "使用者名稱或密碼無效");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
observable.subscribe(disposable);
mCompositeDisposable = new CompositeDisposable();
mCompositeDisposable.add(disposable);
}
private class EditTextMonitor implements TextWatcher {
private PublishSubject<String> mPublishSubject;
EditTextMonitor(PublishSubject<String> publishSubject) {
mPublishSubject = publishSubject;
}
@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) {
mPublishSubject.onNext(s.toString());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mCompositeDisposable.clear();
}
}
複製程式碼
在上面的例子中,我們首先建立了兩個PublishSubject
,分別用於使用者名稱和密碼的訂閱,然後通過combineLatest
對這兩個PublishSubject
進行組合。這樣,當任意一個PublishSubject
傳送事件之後,就會回撥combineLatest
最後一個函式的apply
方法,該方法會取到每個被觀察的PublishSubject
最後一次發射的資料,我們通過該資料進行驗證。
最終執行的效果為:
二、示例解析
2.1 combineLatest 原理
combineLatest
的原理圖如下所示:
Observable
以及一個函式作為引數,並且函式的簽名為這些Observable
發射的資料型別。當以上的任意一個Observable
發射資料之後,會去取其它Observable
最近一次發射的資料,回撥到函式當中,但是該函式回撥的前提是所有的Observable
都至少發射過一個資料項。
2.2 combineLatest 和 zip 的區別
zip
和combineLatest
接收的引數格式相同,我們在 RxJava2 實戰知識梳理(4) - 結合 Retrofit 請求新聞資訊 中用它來實現等待多個Observable
都發射之後才進行資料的組合,回顧一下它的原理圖:
zip
和combineLatest
的區別在於:
zip
是在其中一個Observable
發射資料項後,組合所有Observable
最早一個未被組合的資料項,也就是說,組合後的Observable
發射的第n
個資料項,必然是每個源由Observable
各自發射的第n
個資料項構成的。combineLatest
則是在其中一個Observable
發射資料項後,組合所有Observable
所發射的最後一個資料項(前提是所有的Observable
都至少發射過一個資料項)。
更多文章,歡迎訪問我的 Android 知識梳理系列:
- Android 知識梳理目錄:www.jianshu.com/p/fd82d1899…
- 個人主頁:lizejun.cn
- 個人知識總結目錄:lizejun.cn/categories/