Subject 和 Observable + Observer 的混淆指北[ Android RxJava2 ] ( 這什麼鬼系列 ) 第八話
哇哦, 我們又多了一天時間,所以讓我們來學點新東西好讓這一天過得很棒吧 ?。
各位好, 希望你現在已經做的很好了。 這是我們關於 RxJava2 Android 系列文章的第八話 [ 第一話,第二話,第三話,第四話,第五話,第六話,第七話,第八話 ] 。在這一篇文章中將討論 Rx 中的 Subjects(主題)。
研究動機 : 本文研究動機和系列文章 第一話 中分享給大家的相同。
引言 : 當我開始與 Rx 的這段旅程時, Subjects 就是我最困惑的一個部分。在大多數我開始去讀任一部落格的時候,我總是得到這樣一個定義: “ Subjects 就像一個 Observable 和 Observer 同時存在一樣。” 因為我不是一個聰明的人,所以這一點一直讓我很困惑,因此在用 Rx 做了很多練習之後,有一天我得到了關於 Subjects 的概念,我驚訝於這個概念的強大,所以在這篇文章中我將和你一起討論這個概念以及這個概念有多強大,或許在一些地方我不正確的使用了這個概念,但是這次讓你學到這個概念,在本文最後,你將會和 Subjects 成為很好的朋友。?
如果你和我一樣,認為 Subjects 就像是 Observer 和 Observable 的組合,那麼請儘量忘掉這個概念。現在我將要修改一下 Observable 和 Observer 的概念. 對於 Observable 我會建議你閱讀 Rx Observable 和 開發者 ( 我 ) 之間的對話 [ Android RxJava2 ] (這什麼鬼系列 )第五話 並且 Observer 我會建議你閱讀 繼續 Rx Observable 和 開發者 ( 我 ) 之間的對話 (Observable 求婚 Observer) [ Android RxJava2 ](這什麼鬼系列)第七話 。然後你就可以很輕易的理解本篇文章,現在我會在下面和你分享一下 Obsevable 和 Observer 的一些 API。
這是 Observable 的程式碼,如圖所示程式碼總行數為 3000 多行。 正如我們所知,Observable 通常使用其不同的方法將資料轉換為流,下面我給出一個簡單的例子。
public static void main(String[] args) {
List<String> list = Arrays.asList("Hafiz", "Waleed", "Hussain");
Observable<String> stringObservable = Observable.fromIterable(list);
}
複製程式碼
接下來我們需要 Observer 從 Observable 中得到資料。現在我將第一次向你展示 Obsever 的一些 API。
就像我們看到的 Observer 非常簡單,只有 4 個方法,那現在是時候在示例中使用一下這個 Observer 了。
/**
* Created by waleed on 09/07/2017.
*/
public class Subjects {
public static void main(String[] args) {
List<String> list = Arrays.asList("Hafiz", "Waleed", "Hussain");
Observable<String> stringObservable = Observable.fromIterable(list);
Observer<String> stringObserver = new Observer<String>() {
@Override
public void onSubscribe(Disposable disposable) {
System.out.println("onSubscribe");
}
@Override
public void onNext(String s) {
System.out.println(s);
}
@Override
public void onError(Throwable throwable) {
System.out.println(throwable.getMessage());
}
@Override
public void onComplete() {
System.out.println("onComplete");
}
};
stringObservable.subscribe(stringObserver);
}
}
複製程式碼
它的輸出很簡單. 現在我們成功修訂了 Observable 和 Observer API’s , 當做訂閱時,Observable 基本是呼叫我們的 Observer API’s。
任何時候 Observable 想要提供資料,總是要呼叫 Observaer 的 onNext ( data ) 方法。
任何時候發生錯誤 Observable 會呼叫 Observer 的 onError(e) 方法。
任何時候流操作完成 Observable 會呼叫 Observer 的 onComplete() 方法.
這是這兩個 API 之間的一個簡單關係.
現在我將要開始我們今天的主題,如果再次對 Observable 和 Observer 有任何疑惑,請嘗試閱讀我上文中提到的文章,或者在評論中提問。 我認為 Rx 中關於 Subjects 的定義放到最後討論,現在我將向你解釋一個更簡單的例子,它將使我們可以更直接的掌握 Rx 中 Subjects 的概念。
Observable<String> stringObservable = Observable.create(observableEmitter -> {
observableEmitter.onNext("Event");
});
複製程式碼
這是可以發射一個字串的 Observable。
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
複製程式碼
這是一個將會訂閱 Observable 的消費者。
while (true) {
Thread.sleep(1000);
stringObservable.subscribe(consumer);
}
複製程式碼
這段程式碼會在每一秒後產生一個事件。 為了方便閱讀我把完整的程式碼程式碼貼出。
public class Subjects {
public static void main(String[] args) throws InterruptedException {
Observable<String> stringObservable = Observable.create(observableEmitter -> {
observableEmitter.onNext("Event");
});
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
while (true) {
Thread.sleep(1000);
stringObservable.subscribe(consumer);
}
}
}
複製程式碼
Output: Event Event Event Event
這是一個簡單的例子,我認為沒有必要過多的解釋,現在有趣的部分是,我會用不同的技術來寫出會有一樣輸出的新的例子。 在深入之前,嘗試閱讀下面的程式碼。
class ObservableObserver extends Observable<String> implements Observer<String>.
複製程式碼
這很簡單,我建立了一個名為 ObservableObserver 的新類, 它繼承自 Observable 並且實現了 Observer 介面。 所以這意味這它可以作為 Observable 加強版 和 Observer. 我不認為這會有任何疑問,所以我們已經知道 Observable 總是會生成流,所以這個類也有這個能力,因為它繼承自 Observable。然後我們可知 Observer 可以通過 訂閱 Observable 來觀察 Observable 中的任何流,那麼我們的新類也可以完成這些工作,因為它實現了 Observer 介面,BOOM。 很簡單。 現在我要給你看全部程式碼,程式碼只是為了解釋這個概念並不意味著它是一個 成熟 的程式碼。
class ObservableObserver extends Observable<String> implements Observer<String> {
private Observer<? super String> observer;
@Override
protected void subscribeActual(Observer<? super String> observer) { // Observable abstract method
this.observer = observer;
}
@Override
public void onSubscribe(Disposable disposable) { //Observer API
if (observer != null) {
observer.onSubscribe(disposable);
}
}
@Override
public void onNext(String s) {//Observer API
if (observer != null) {
observer.onNext(s);
}
}
@Override
public void onError(Throwable throwable) {//Observer API
if (observer != null) {
observer.onError(throwable);
}
}
@Override
public void onComplete() {//Observer API
if (observer != null) {
observer.onComplete();
}
}
public Observable<String> getObservable() {
return this;
}
}
複製程式碼
又一個很簡單的類,我們已經使用過上面的所有方法了,只是在這裡有一個區別,就是我們在同一個類中使用了 Observable 和 Observer 的相關方法。
public static void main(String[] args) throws InterruptedException {
ObservableObserver observableObserver = new ObservableObserver();
observableObserver.getObservable().subscribe(System.out::println);
while (true) {
Thread.sleep(1000);
observableObserver.onNext("Event");
}
}
複製程式碼
Output: Event Event Event
在上面的程式碼中有兩行很重要,我將要給大家解釋一下: **observableObserver.getObservable(): **這裡,我從 ObservableObserver 類獲取 Observable 並訂閱 Observer . **observableObserver.onNext(“Event”): **這裡,當事件發生時呼叫 Observer API 方法. 因為作為一個自我閉環的類,所以我能夠從這個既是 Observabel 又是 Observer 的類中獲得好處。現在有一個驚喜,你已經掌握了 Subjects 的概念,如果你不信的話來看下面圖中的程式碼:
這是 RxJava2 Subject 類的程式碼,現在你可以明白為什麼人們會說 Subjiects 既是 Observable 又是 Observer,因為它使用了兩個的 API 方法。 現在的 RxJava 中可以使用不同型別的 Subjects, 這是我們下面要討論的內容。
在 RxJava 中你可以獲取到 4 種型別的 Subjiects。 1. Publish Subject 2. Behaviour Subject 3. Replay Subject 4. Async Subject
public static void main(String[] args) throws InterruptedException {
Subject<String> subject = PublishSubject.create();
// Subject<String> subject = BehaviorSubject.create();
// Subject<String> subject = ReplaySubject.create();
// Subject<String> subject = AsyncSubject.create(); I will explain in the end
subject.subscribe(System.out::println);
int eventCounter = 0;
while (true) {
Thread.sleep(100);
subject.onNext("Event "+ (++eventCounter));
}
}
複製程式碼
Output: Event 1 Event 2 Event 3 Event 4 Event 5 Event 6 Event 7 Event 8 Event 9 Event 10
一般來說如果你執行上面的程式碼,你將會看到輸出中除了 AsyncSubject 的其他 Subjects 輸出都是相同的,現在是時候來區別一下這些 Subjects 的型別了。 **1. Publish Subject: **在該型別 Subject 中,我們可以獲取實時的資料,例如我的一個 Publish Subject 是獲取感測器資料,那麼現在我訂閱了該 Subject, 我將之獲取最新的值,示例如下:
public static void main(String[] args) throws InterruptedException {
Subject<String> subject = PublishSubject.create();
int eventCounter = 0;
while (true) {
Thread.sleep(100);
subject.onNext("Event " + (++eventCounter));
if (eventCounter == 10)
subject.subscribe(System.out::println);
}
}
複製程式碼
Output: Event 11 Event 12 Event 13 Event 14 Event 15 Event 16
所以,在這裡 publish subject 釋出資料是從 0 開始,而在訂閱的時候已經發布到了 10,正如你所見,輸出的資料為 Event 11。
**2. Behaviour Subject: **在這種型別的 Subjects 中,我們將獲取這個 Subject 最後釋出出的值和新的將要發出的值,為了簡單起見,請閱讀下面的程式碼。
public static void main(String[] args) throws InterruptedException {
Subject<String> subject = BehaviorSubject.create();
int eventCounter = 0;
while (true) {
Thread.sleep(100);
subject.onNext("Event " + (++eventCounter));
if (eventCounter == 10)
subject.subscribe(System.out::println);
}
}
複製程式碼
Output: Event 10 Event 11 Event 12 Event 13 Event 14 Event 15
正如輸出中你所看到的那樣,我也獲得了 “ Event 10” 這個值,並且這個值在我訂閱之前就已經發布了。這意味著如果我想要訂閱之前的最後一個值的話,我可以使用這個型別的 Subject。
**3. Replay Subject: **在這個型別的 Subject 中,當我訂閱時可以沒有顧及的獲得所有釋出的資料值,簡單起見還是直接上程式碼吧。
public static void main(String[] args) throws InterruptedException {
Subject<String> subject = ReplaySubject.create();
int eventCounter = 0;
while (true) {
Thread.sleep(100);
subject.onNext("Event " + (++eventCounter));
if (eventCounter == 10)
subject.subscribe(System.out::println);
}
}
複製程式碼
Output: Event 1 Event 2 Event 3 Event 4 Event 5 Event 6 Event 7 Event 8 Event 9 Event 10 Event 11 Event 12
現在我再次在 event 10 的時候訂閱,但是我可以獲得所有的歷史資料,所以這很簡單嘛。
**4. Async Subject: **在這個型別的 Subject 中,我們將獲得最後釋出的資料值,這個資料值是 Subject 在完成和終止前發射的,為了簡單起見,依舊是直接上程式碼吧。
public static void main(String[] args) throws InterruptedException {
Subject<String> subject = AsyncSubject.create();
subject.subscribe(System.out::println);
int eventCounter = 0;
while (true) {
Thread.sleep(100);
subject.onNext("Event " + (++eventCounter));
if (eventCounter == 10) {
subject.onComplete();
break;
}
}
}
複製程式碼
Output: Event 10 Process finished with exit code 0
在這裡,你可以看到在值為 10 的時候以完成標識結束了 Subject 並且在程式完成後和程式退出之前,我得到了輸出的 Event 10 ,所以這意味著它的意思是任何時候我想要通過 Subject 獲得最後一次釋出的的資料值可以使用 Async Subject。
再次重複一下: Publish Subject: 我不關心之前的釋出歷史,我只關心新的或者最新的值。 Behaviour Subject: 我關心該 Subject 釋出的最後一個值和新值。 Replay Subject: 我關心所有釋出了新值的歷史資料。 Async Subject: 我只關心在完成或終止之前由主題發出的最後一個值。
總結: 你好呀朋友,希望你對這個知識點已經很清晰了,另外盡你最大的努力去動手實踐這些概念,現在,我想要和各位說再見了,還有祝大家有個愉快的週末。 ?
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。