RxJava基本原理與使用(二)

LeiHolmes發表於2017-10-31

###前言
  上一篇我們瞭解了RxJava的介紹以及通過一個例子學習了RxJava的展現形式,相信大家現在已經對RxJava有一個初步的印象與概念了。本篇我們將更深入的學習RxJava的基本原理以及如何使用RxJava。

###觀察者模式
  上一篇有提到RxJava的核心便是擴充套件的觀察者模式,我們先來學習一下觀察者模式。

  事件:小明按下遙控器開關,空調啟動並開始吹風了。按下製冷按鍵,空調吹出的風變為涼風。再按下3檔風速按鍵,空調吹的風變大了。
  在這個事件中,空調作為觀察者,遙控器作為被觀察者,空調通過紅外線檢測遙控器傳來的訊號並作出響應。

  通過上圖我們可以很清晰的看出遙控器作為事件的生產方主動發起事件,是事件的起點,而空調作為事件的處理方被動接收事件做出響應,是事件的終點。而在事件傳遞的過程中可對事件進行過濾,轉換,合併等操作,就像例子中製冷與加大風速的效果。
  這個概念是RxJava中的核心,它是基於觀察者模式來組建自己的程式邏輯,遙控器就相當於RxJava的被觀察者Observable,空調相當於觀察者Observer,而對事件處理的一些操作相當於各類操作符。不同的是RxJava中觀察者需要對被觀察者進行訂閱,這樣當被觀察者發出事件時,觀察者才會接收到事件進行處理。若未進行訂閱,被觀察者是不會發出任何事件的。

使用

  瞭解了觀察者模式,接下來動起指尖嘗試下怎麼使用RxJava。

建立被觀察者Observable

  第一步:建立被觀察者Observable:

Observable<Object> observable = Observable.create(new Observable.OnSubscribe<Object>() {
    @Override
    public void call(Subscriber<? super Object> subscriber) {
        //被觀察者的資料操作更新
        for (int i = 0; i < 5; i++)
            subscriber.onNext("xulei" + i);
        }
        subscriber.onCompleted();
    }
});複製程式碼

  通過Observable.create()方法建立並返回一個Observable物件,create()方法需要一個OnSubsribe物件作為引數傳入並執行call()方法。此OnSubsribe物件繼承自Action1。
  而在call()方法中可通過subscriber.onNext()進行事件的傳送,subscriber.onCompleted()標記為事件傳送完畢。subscriber.onError()標記為事件傳送過程出現異常。
  除create()方法建立Observable方式外,還可以使用just()與from()等方式,這個在之後的建立操作符文章中會有講解。

建立觀察者Observer

  第二步:建立觀察者Observer:

Observer observer = new Observer() {
    @Override
    public void onCompleted() { //標記事件傳送完畢的回撥
        Log.e("rx_test", "onCompleted");
    }
    @Override
    public void onError(Throwable e) { //事件傳送過程出現異常的回撥
        Log.e("rx_test", "onError");
    }
    @Override
    public void onNext(Object o) { //接收到傳送事件的回撥
        Log.e("rx_test", "onNext:" + o.toString());
    }
};複製程式碼

  在以往普通的觀察者模式中,觀察者通常只提供一個update()的方法,而RxJava擴充套件的觀察者模式中的觀察者提供onNext(Object o)onCompleted()onError(Throwable e)三個方法,分別對應被觀察者call()方法中重寫的subscriber.onNext()subscriber.onCompleted()subscriber.onError()方法。而onNext()方法就對應普通觀察者模式中的update()方法。
  RxJava擴充套件的觀察模式彌補了普通觀察者模式的不足:
  1. 當事件傳送完畢可以呼叫onCompleted()方法進行標示。
  2. 當事件傳送過程中出現異常會自動觸發onError()方法,也可進行手動呼叫。
  3. Observable支援鏈式程式設計,從而避免了回撥巢狀的問題,也簡化了程式碼。

訂閱

  最後一步:被觀察者Observable訂閱觀察者Observer。
  這裡不同於普通觀察者模式,上一篇我們講了在RxJava擴充套件觀察者模式中,如果沒有觀察者,被觀察者是不會發出任何事件的。所以這裡是被觀察者訂閱觀察者。

observable.subscribe(observer);複製程式碼

  訂閱很簡單,一行程式碼搞定。呼叫Observable的subscribe()方法,傳入觀察者物件作為引數,這樣被觀察者與觀察者就進行了繫結。

簡寫

  RxJava可以使用鏈式程式設計:

Observable.create(new Observable.OnSubscribe<Object>() {
    @Override
    public void call(Subscriber<? super Object> subscriber) {
        //被觀察者的資料操作更新
        for (int i = 0; i < 5; i++) {
            subscriber.onNext("xulei" + i);
        }
        subscriber.onCompleted();
    }
}).subscribe(new Observer<Object>() {
    @Override
    public void onCompleted() {
        Log.e("rx_test", "onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.e("rx_test", "onError");
    }
    @Override
    public void onNext(Object o) {
        Log.e("rx_test", "onNext:" + o.toString());
    }
});複製程式碼

邏輯梳理

  到此一個RxJava的簡單呼叫就實現了,相信不少碼友看完之後還是很懵13,那我們再來梳理一下整個流程。首先使用Observable.create()建立了一個Observable,並在create()方法中傳入了一個OnSubscribe物件作為引數,重寫OnSubscribe中的call()方法,當Observable進行訂閱後就會自動觸發call()方法傳送事件。
  注意:call()方法中的subscriber引數其實就是我們在呼叫subscribe()進行訂閱時時傳入的觀察者Observer。所以當在call()方法中呼叫的5次onNext()方法與1次onCompleted()方法後,觀察者Observer中輸出的日誌為:

onNext:xulei0
onNext:xulei1
onNext:xulei2
onNext:xulei3
onNext:xulei4
onCompleted複製程式碼

  有的碼友看到這裡會對call()方法中的subscriber引數就是訂閱時傳入的Observer有些不解,那麼我們一起來看原始碼。
  先看下call()方法中的引數Subscriber:

public abstract class Subscriber<T> implements Observer<T>, Subscription {
    ......
}複製程式碼

  可以看出Subscriber是Observer的抽象實現類,與Observer一個型別。再來看訂閱時呼叫的subscribe(observer)方法:

public final Subscription subscribe(final Observer<? super T> observer) {
    //無視
    if (observer instanceof Subscriber) {
        return subscribe((Subscriber<? super T>)observer);
    }
    return subscribe(new Subscriber<T>() {

        @Override
        public void onCompleted() {
            observer.onCompleted();
        }

        @Override
        public void onError(Throwable e) {
            observer.onError(e);
        }

        @Override
        public void onNext(T t) {
            observer.onNext(t);
        }
    });
}複製程式碼

  這裡將傳入的Observer物件通過代理轉換為Subscriber物件作為引數傳入並呼叫過載方法subscribe(),我們再來看這個subscribe()方法的程式碼:

public final Subscription subscribe(Subscriber<? super T> subscriber) {
    return Observable.subscribe(subscriber, this);
}複製程式碼

  這裡繼續呼叫過載方法subscribe(),將由Observer轉換為的subscriber物件與當前Observable物件作為引數傳入,繼續往下追蹤原始碼:

private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
    ......
    subscriber.onStart();
    ......
    try {
        hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
        return hook.onSubscribeReturn(subscriber);
    } catch (Throwable e) {
        ......
        return Subscriptions.unsubscribed();
    }
}複製程式碼

  精簡一下程式碼發現,subscriber.onStart()用來通知被觀察者準備開始傳送事件了。重點看hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);我們發現hook.onSubscribeStart(observable, observable.onSubscribe)方法返回的是其第二個引數observable.onSubscribe,這個引數正是新建Observable時create()方法中傳入的OnSubscribe物件。接著又通過這個onSubscribe呼叫call(subscriber)方法,將subscriber作為引數傳入,碼友們有沒有發現,這個subscriber傳來傳去究其根源,正是一開始由訂閱方法subscribe(observer)傳入的observer通過代理轉換為的那個subscriber。
  這樣前後邏輯就連線上了,通過閱讀原始碼我們才能發現為何建立Observable時call()方法中的subscriber引數其實就是訂閱時傳入的Observer。

總結

  到此,本篇關於RxJava的基本原理與使用就講解完畢了,下一篇我們將一起研究RxJava的四類操作符中的建立操作符都有哪些以及如何使用。
  這裡感謝下張磊大神撰寫的RxJava系列的幫助:
  RxJava系列2(基本概念及使用介紹)
  技術渣一枚,有寫的不對的地方歡迎大神們留言指正,有什麼疑惑或者建議也可以在我Github上RxJavaDemo專案Issues中提出,我會及時回覆。
  附上RxJavaDemo的地址:
  RxJavaDemo

相關文章