在平時的應用中,咱們常常會讓用戶輸入一些信息,最多見的莫過於註冊或者登陸界面中,讓用戶輸入用戶名或者密碼,可是咱們常常會對用戶名或者密碼有必定的要求,只有當它們同時知足要求時,才容許用戶進行下一步的操做。java
這個需求就涉及到一種模型,即在多個地方監聽變化,可是在一個地方進行統一驗證,若是驗證成功,那麼容許用戶進行下一步的操做,不然提示用戶輸入不正確。app
經過這個例子,你們將學習到combineLatest
操做符的用法。ide
在下面這個示例中,包含了兩個輸入框,分別對應用戶名和密碼,它們的長度要求分別爲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
最後一次發射的數據,咱們經過該數據進行驗證。學習
最終運行的效果爲: spa
combineLatest
的原理圖以下所示: code
Observable
以及一個函數做爲參數,而且函數的簽名爲這些
Observable
發射的數據類型。當以上的任意一個
Observable
發射數據以後,會去取其它
Observable
最近一次發射的數據,回調到函數當中,可是該函數回調的前提是全部的
Observable
都
至少發射過一個數據項。
zip
和combineLatest
接收的參數格式相同,咱們在 RxJava2 實戰知識梳理(4) - 結合 Retrofit 請求新聞資訊 中用它來實現等待多個Observable
都發射以後才進行數據的組合,回顧一下它的原理圖: cdn
zip
和
combineLatest
的區別在於:
zip
是在其中一個Observable
發射數據項後,組合全部Observable
最先一個未被組合的數據項,也就是說,組合後的Observable
發射的第n
個數據項,必然是每一個源由Observable
各自發射的第n
個數據項構成的。combineLatest
則是在其中一個Observable
發射數據項後,組合全部Observable
所發射的最後一個數據項(前提是全部的Observable
都至少發射過一個數據項)。