擁抱RxJava(二):Observable究竟如何封裝資料?

W_BinaryTree發表於2019-03-04

這一系列文章本來我發表在簡書。最近開始轉移到掘金。以後也會在掘金發表(慢慢拋棄簡書了應該,掘金的技術環境確實比簡書好些)。

上篇簡單講到了一些關於Event/Rx bus的優缺點。並且提到了如何“正確”使用RxJava,而不是使用RxBus來自己重新發明輪子。

放棄RxBus,擁抱RxJava(一):為什麼避免使用EventBus/RxBus

其中也講到了一個簡單使用 create() 方法來進行封裝Observable。但也留下了許多坑,比如記憶體洩漏,不能Multicast(多個Subscriber訂閱同一個Observable) 等問題。所以這篇,我們接著通過這個例子,來具體瞭解下,如何封裝Observable。

1. Observable提供的靜態方法都做了什麼?

首先我們來簡單看一下Observable的靜態方法,just/from/create都怎麼為你提供Observable。
我們先看just:

public static <T> Observable<T> just(T item) {
    ObjectHelper.requireNonNull(item, "The item is null");
    return RxJavaPlugins.onAssembly(new ObservableJust<T>(item));
}複製程式碼

我們暫時不需要糾結 RxJavaPlugins.onAssembly() 這個方法。比較重要的是 just(T item) 方法會為你提供一個 ObservableJust(item) 的例項,而這個 ObservableJust 類,就是一個RxJava內部的實現類。
在 RxJava 2.x 中 Observable 是一個抽象類,只有一個抽象方法,subscribeActual(Observer observer);(但是Observable的原始碼足足有13518行!!!)

public abstract class Observable<T> implements ObservableSource<T>{
  //implemented methods

  protected abstract void subscribeActual(Observer<? super T> observer);

  //other implements/operators
}複製程式碼

那麼ObservableJust這個類究竟什麼樣呢?

public final class ObservableJust<T> extends Observable<T> implements ScalarCallable<T> {

    private final T value;
    public ObservableJust(final T value) {
        this.value = value;
    }

    @Override
    protected void subscribeActual(Observer<? super T> s) {
        ScalarDisposable<T> sd = new ScalarDisposable<T>(s, value);
        s.onSubscribe(sd);
        sd.run();
    }

    @Override
    public T call() {
        return value;
    }
}複製程式碼

我們首先看到構造方法裡,直接把value賦給了ObservableJust的成員。這也就是為什麼Observable.just()裡的程式碼會直接執行,而不是像create()方法,有Subscriber時候才能執行(Observable.create的初始化方法在subscribeAcutal裡執行)。
再來看看兩個item的just(T item1,T item2):

public static <T> Observable<T> just(T item1, T item2) {
    ObjectHelper.requireNonNull(item1, "The first item is null");
    ObjectHelper.requireNonNull(item2, "The second item is null");

    return fromArray(item1, item2);
}複製程式碼

誒?怎麼畫風突變?不是ObservableJust了?其實除了只有一個item的just,其他的just方法也都是呼叫了這個fromArray。那我們來看看這個fromArray:

public static <T> Observable<T> fromArray(T... items) {
    //NullCheck
    return RxJavaPlugins.onAssembly(new ObservableFromArray<T>(items));
}複製程式碼

前面一些check我們忽略,這裡我們發現一些熟悉的身影了ObservableFromArray(items)。又一個Observable的實現類。

public final class ObservableFromArray<T> extends Observable<T> {
    final T[] array;
    public ObservableFromArray(T[] array) {
        this.array = array;
    }
    @Override
    public void subscribeActual(Observer<? super T> s) {
        FromArrayDisposable<T> d = new FromArrayDisposable<T>(s, array);
        s.onSubscribe(d);
        d.run();
    }

    static final class FromArrayDisposable<T> extends BasicQueueDisposable<T> {
      //implements
    }
}複製程式碼

是不是更熟悉?其實Observable幾乎所有的靜態方法和操作符都是這樣,甚至包括一些著名的RxJava庫比如RxBinding,也都是使用這種封裝方法。內部實現Observable的subscribeActual()方法。對外只提供靜態方法來為你生成Observable。為什麼這麼做,我們來了解一下subscribeActual()方法。

2. subscribeActual() 究竟是什麼?

subscribeActual()其實就是Observable和Observer溝通的橋樑。這個Observer(Subscriber)就是你在Observable.subscribe()方法裡寫的那個類,或者是Consumer(只處理onNext方法)。

public final void subscribe(Observer<? super T> observer) {
        //NullCheck&Apply plugin
        subscribeActual(observer);

}複製程式碼

我們看到其實這個方法除了Check和Apply就只有這一行subscribeActual(observer),連線了Observable和Observer。所以我們知道了,subscribeActual()方法裡的程式碼,只有在subscribe()呼叫後,才回撥用。

那麼他們是如何連結的呢?其實很簡單,根據你的邏輯一句一句的呼叫observer.onXX()方法就可以了。比如剛才我們看到的ObservableJust:

@Override
public void run() {
    if (get() == START && compareAndSet(START, ON_NEXT)) {
        observer.onNext(value);
        if (get() == ON_NEXT) {
            lazySet(ON_COMPLETE);
            observer.onComplete();
        }
    }
}複製程式碼

再比如我們的ObservableFromArray:

void run() {
    T[] a = array;
    int n = a.length;

    for (int i = 0; i < n && !isDisposed(); i++) {
        T value = a[i];
        if (value == null) {
            actual.onError(new NullPointerException("The " + i + "th element is null"));
            return;
        }
        actual.onNext(value);
    }
    if (!isDisposed()) {
        actual.onComplete();
    }
}複製程式碼

複雜點的例子,比如如何封裝button的OnClick事件:

@Override protected void subscribeActual(Observer<? super Object> observer) {
  if (!checkMainThread(observer)) {
    return;
  }
  Listener listener = new Listener(view, observer);
  observer.onSubscribe(listener);
  view.setOnClickListener(listener);
}

static final class Listener extends MainThreadDisposable implements OnClickListener {
  private final View view;
  private final Observer<? super Object> observer;

  Listener(View view, Observer<? super Object> observer) {
    this.view = view;
    this.observer = observer;
  }

  @Override public void onClick(View v) {
    if (!isDisposed()) {
      observer.onNext(Notification.INSTANCE);
    }
  }

  @Override protected void onDispose() {
    view.setOnClickListener(null);
  }
  }
}複製程式碼

但是細心的同學應該看到了,每個subscribeActual()方法裡,都會有 observer.onSubscribe(disposable)這句。那麼這句又是做什麼的呢?根據Observable Contract,onSubscribe是告知已經準備好接收item。而且通過這個方法將Disposable傳回給Subscriber。
Disposable其實就是控制你取消訂閱的。他只有兩個方法 dispose() 取消訂閱,和 isDisposed() 來通知是否已經取消了訂閱。
取消訂閱時,要根據需求釋放資源。
在subscribeActual()裡邏輯要嚴謹,比如onComplete()之後不要有onNext()。需要注意的點很多,所以可能這也就是為什麼RxJava推薦使用者使用靜態方法生成Observable吧。如果有興趣,可以直接閱讀

Observable Contract

3 Observable.create()

create()方法是一個歷史遺留問題了。由於這個命名,很多人都覺得Observable.create()不就應該是生成Obseravble最先想到的方法嗎? 在 RxJava 1.x 這是錯誤的,Observable.create()在 1.x 版本幾乎飽受詬病。不是他不好,而是他太難操控。 RxJava一定要遵循Observable Contract才會按照預期執行,而使用create()你可以完全無視這個規則。你可以在onComplete之後繼續傳送onNext事件,下游仍會收到事件。如果在1.x想正確的使用Observable.create()你必須首先了解幾乎所有的規則。所以一直以來 RxJava 1.x 版本使用Observable.create是不推薦的。(在新版的RxJava 1.3中,create()方法已經標記@deprecated

在經歷了1.x的失敗後,RxJava 2.x 提供了安全的create()方法。他通過ObservableEmitter作為中間人,代替處理。使得即便你在Emitter中沒有參照ObservableContract,下游仍會按照預期的進行。

4 關於操作符

我們上文說到的just,from,create等等是生成Observable的操作符,那麼如map,filter等等的操作符會有什麼區別嗎?
我們來看下原始碼:
map:

public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
    ObjectHelper.requireNonNull(mapper, "mapper is null");
    return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}複製程式碼

filter:

public final Observable<T> filter(Predicate<? super T> predicate) {
    ObjectHelper.requireNonNull(predicate, "predicate is null");
    return RxJavaPlugins.onAssembly(new ObservableFilter<T>(this, predicate));
}複製程式碼

我們看到,這個區別就是在生成新Observable的時候,會需要兩個引數,一個是這個Observable本身,也就是程式碼中的this,另一個就是需要進行操作的介面實現(當然也有更多引數的比如Schduler等等,大同小異,不再贅述)。而這個Observable本身,也就是我們口中常說的上游。上游下游是根據操作符的來說,對於一個操作符,在這個操作符之前的就是上游,而這個操作符之後的就是下游。
比如我們的map:

public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
    @Override
    public void subscribeActual(Observer<? super U> t) {
        source.subscribe(new MapObserver<T, U>(t, function));
    }
}複製程式碼

source就是我們的上游。而這個MapObserver就是我們的中間人(其實也算是操作符本身),將資料根據需求,處理後發給下游。
操作符原理非常複雜,map可以說是最簡單的了。如果有興趣我推薦可以看一下publish(selector)等等複雜的操作符。更深入理解操作符。當然,有毅力的同學也可以關注RxJava 主要負責人的系列部落格(純英文,而且很難懂,不是英語難懂,是原理很難懂)。

Advanced Reactive Java

關於lift

讀過扔物線大神文章入門的同學應該對lift有一個瞭解。RxJava 1.x 幾乎所有操作符都是基於lift完成的。但是RxJava 2.x 可以說幾乎看不到lift。 目前lift僅僅作為提供自定義操作符的一個介面(雖然更推薦使用簡單好用的compose,因為lift需要複寫七個抽象方法。)。
最後再說一下幾點:

  • Flowable:Floawble其實在實現上和Observable類似,區別是Observable同過 Disposable控制取消訂閱。而Flowable同過Subscription。其中還需要request()方法控制流量。具體關於這個問題,我推薦這篇文章

    給初學者的RxJava2.0教程

總結:

  • 我們從原始碼分析角度來說,RxJava 2.x 也是同過subscribeActual來連結Observable和Observer(Subscriber)。本質上和Listener沒什麼太大區別。但是,RxJava的確是諸多一線Java/Android開發者的結晶。豐富的操作符,執行緒排程等等諸多優勢。而且保證型別安全。這裡再次感謝他們,畢竟我們還是站在他們肩膀上程式設計

小彩蛋:關於Reactive Streams 和 RxJava

其實 Reactive Programming在Java上的實現不止 RxJava 一個。比較出名的還有Project Reactor和 google 的 agera 等等。 但是綜合考慮,無論是效能,擴充套件性上RxJava在Android平臺上是最優秀的。 由於都在JVM上,大家都決定統一介面所以推出 Reactive Streams定義了這一套的幾個基本介面:

包括了 :

//對應RxJava中的Flowable
public interface Publisher<T> {
    public void subscribe(Subscriber<? super T> s);
}

//RxJava並沒有直接對應,而是各種形式的實現類。
public interface Subscriber<T> {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
}

//同上,RxJava在flowable中直接使用Subscription
public interface Subscription {
    public void request(long n);
    public void cancel();
}

//Flowable版本的Subject
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}複製程式碼

正因為這四個介面的命名關係。本在RxJava 1.x 的Observable改名為Flowable。而RxJava 2.x的 Observable是完全沒有backpressure支援。因為起名衝突的原因,將本來的Subscription改為Disposable,Subscriber改為Observer。

相關文章