引言
經過幾年的發展,響應式程式設計已經是很流行了,在Android開發中的應用也非常的廣泛,身為Android開發者,則是必須掌握的技術。
正文
網上已經有很多很多RxJava相關的文章,視訊等等教程,但是說實話對於入門,或者新手來說,確實不好理解,上來就是各種,觀察者、被觀察者、訂閱、釋出等等概念,一遍看下來直接就暈了,就感覺RxJava很難,難理解,用的時候也只是依葫蘆畫瓢,暈乎乎的用著,然後就沒有然後了。
這裡我都不說那些概念,因為講概念太抽象,難記住,更難理解。我們用另外一個視角來學習。因為RxJava 1.x的版本 官方已經停止更新了維護了,沒有學習過也沒有關係,RxJava 2.x是全新的,直接學習使用就好了。
首先假設我們在工廠裡上班,工廠都會有流水線,產品經過流水線生產後來訂單了銷售出去。
這裡假設工廠生產的是一種六邊形的“Jerry帥氣餅乾”,上游是生產車間流水線的事件流,下游是訂單產品的銷售消費事件流。中間連線上下游關係的暫且叫做“Jerry帥氣餅乾生產消費訂單管理系統”(不要臉,名字寫這麼長),為了下文方便抒寫且用“生產訂單管理系統”(PCMS)。以上圖上下游對應的就是Obsersvable被觀察者也是釋出者,下游對應Observer觀察者也是訂閱者。使用RxJava程式碼表示上圖就是:
public void test1() {
// 上游生成產品流水線
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.d(TAG, "test1 ====== Observable: ------ onNext: Jerry");
emitter.onNext("Jerry");
Log.d(TAG, "test1 ====== Observable: ------ onNext: 就是");
emitter.onNext("就是");
Log.d(TAG, "test1 ====== Observable: ------ onNext: 帥");
emitter.onNext("帥");
Log.d(TAG, "test1 ====== Observable: ------ onNext: !!!");
emitter.onNext("!!!");
Log.d(TAG, "test1 ====== Observable: ------ onComplete");
emitter.onComplete();
Log.d(TAG, "test1 ====== Observable: ------ onNext: Jerry帥炸天!!!");
emitter.onNext("Jerry帥炸天!!!");
}
});
// 下游訂單產品銷售
Observer<String> observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "test1 ====== Observer: onSubscribe");
}
@Override
public void onNext(String value) {
Log.d(TAG, "test1 ====== Observer: onNext: " + value);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "test1 ====== Observer: onError: " + e.getMessage());
}
@Override
public void onComplete() {
Log.d(TAG, "test1 ====== Observer: onComplete");
}
};
// 連線上下游的訂單管理系統
observable.subscribe(observer);
}
複製程式碼
上述程式碼,上游生產車間流水線就是Observable,下游訂單銷售就是Observer,中間通過“生產訂單管理系統”subscribe來將上下游連線起來。
執行後輸出結果是:
從輸出結果來看,當上遊Observable發出一個生產的餅乾產品事件,下游訂單銷售的Observer就銷售一個餅乾產品事件,而且當上遊呼叫了onComplete方法後,上游的生產事件還是生產餅乾事件(繼續生產了“Jerry帥炸天”餅乾事件),但是下游的訂單銷售卻沒有消費掉。也就是事件產生方呼叫onComplete方法後,之後的事件還會繼續傳送,但是事件接收方就不會接收了。
我們來看看Observable的subscribe方法的引數:ObservableEmitter,Emitter顧名思義是發射器的意思,ObservableEmitter介面繼承自Emitter介面:
public interface Emitter<T> {
/**
* Signal a normal value.
* @param value the value to signal, not null
*/
void onNext(T value);
/**
* Signal a Throwable exception.
* @param error the Throwable to signal, not null
*/
void onError(Throwable error);
/**
* Signal a completion.
*/
void onComplete();
}
複製程式碼
介面定義很簡單,就三個方法,onNext我們上門已經用過了,是用來發射傳送事件的,onComplete是用來表示事件傳送完了,後面如果有新的事件傳送,下游接收者可以不用處理,onError方法看註釋說是傳送一個異常事件給下游接收者。到底是不是這樣,我們來試試就曉得了。
public void test2() {
// 上游生成產品流水線
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.d(TAG, "test2 ====== Observable: ------ onNext: Jerry");
emitter.onNext("Jerry");
Log.d(TAG, "test2 ====== Observable: ------ onNext: 就是");
emitter.onNext("就是");
Log.d(TAG, "test2 ====== Observable: ------ onNext: 帥");
emitter.onNext("帥");
Log.d(TAG, "test2 ====== Observable: ------ onNext: !!!");
emitter.onNext("!!!");
Log.d(TAG, "test2 ====== Observable: ------ onError");
emitter.onError(new IllegalStateException("Jerry餅乾烤焦了,賣出去會被打!"));
Log.d(TAG, "test2 ====== Observable: ------ onNext: Jerry帥炸天!!!");
emitter.onNext("Jerry帥炸天!!!");
}
});
// 下游訂單產品銷售
Observer<String> observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "test2 ====== Observer: onSubscribe");
}
@Override
public void onNext(String value) {
Log.d(TAG, "test2 ====== Observer: onNext: " + value);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "test2 ====== Observer: onError: " + e.getMessage());
}
@Override
public void onComplete() {
Log.d(TAG, "test2 ====== Observer: onComplete");
}
};
// 連線上下游的訂單管理系統
observable.subscribe(observer);
}
複製程式碼
在上游生產餅乾的時候就生產了一個“Jerry餅乾烤焦了,賣出去會被打!”的錯誤餅乾事件,下游訂單銷售的onError出錯狀態會消費這個事件。而上游在出錯事件後傳送的“Jerry帥炸天!!!”餅乾事件,同樣也只是把事件傳送了處理,下游訂單銷售並沒有接收處理這個事件。
執行後輸出結果:
細心的小夥伴應該會發現,每次執行的時候都會先呼叫下游的onSubscribe方法,這個方法裡有個引數Disposable(用完即可丟棄)意思可以理解成,將上下游的連線切斷,讓上游的生產的餅乾不打包放入下游訂單銷售環節,實際開發中是有這種需求的,當傳送事件出問題的時候就需要斷開事件接收處理。不像最近的疫苗事件,一些不要臉的生物疫苗公司把生產不合格的疫苗上市銷售,傷天害理,謀財害命。下面舉個例子:
public void test3() {
// 上游生成產品流水線
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.d(TAG, "test3 ====== Observable: ------ onNext: Jerry");
emitter.onNext("Jerry");
Log.d(TAG, "test3 ====== Observable: ------ onNext: 就是");
emitter.onNext("就是");
Log.d(TAG, "test3 ====== Observable: ------ onNext: 帥");
emitter.onNext("帥");
Log.d(TAG, "test3 ====== Observable: ------ onNext: !!!");
emitter.onNext("!!!");
Log.d(TAG, "test3 ====== Observable: ------ onComplete");
emitter.onComplete();
Log.d(TAG, "test3 ====== Observable: ------ onNext: Jerry帥炸天!!!");
emitter.onNext("Jerry帥炸天!!!");
}
});
// 下游訂單產品銷售
Observer<String> observer = new Observer<String>() {
private Disposable mDisposable;
private int i;
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "test3 ====== Observer: onSubscribe");
mDisposable = d;
}
@Override
public void onNext(String value) {
Log.d(TAG, "test3 ====== Observer: onNext: " + value);
i++;
// 第一個事件接收後,就斷開上下游連線
if (i == 1) {
Log.d(TAG, "test3 ====== Observer: start disposable");
mDisposable.dispose();
Log.d(TAG, "test3 ====== Observer: isDisposable: " + mDisposable.isDisposed());
}
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "test3 ====== Observer: onError: " + e.getMessage());
}
@Override
public void onComplete() {
Log.d(TAG, "test3 ====== Observer: onComplete");
}
};
// 連線上下游的訂單管理系統
observable.subscribe(observer);
}
複製程式碼
這裡我們在下游訂單銷售的onNext方法中,當接收完第一個餅乾事件後,就使用mDisposable.dispose()方法將上下游的連線斷開了,斷開後上遊後續生產的餅乾事件,下游就接收不到。
執行的結果:
上圖中,也驗證了我們的猜想,當使用dispose斷開上下游連線後,下游就無法再繼續接收事件了。
這一講就先介紹這麼多,這樣的方式理解Observable和Observer以及訂閱動作subscribe是不是容易多了,希望對你有所幫助,下一講使用RxJava來切換變化餅乾事件處理的執行緒(主執行緒、子執行緒)。