這一系列文章本來我發表在簡書。最近開始轉移到掘金。以後也會在掘金發表(慢慢拋棄簡書了應該,掘金的技術環境確實比簡書好些)。
上篇簡單講到了一些關於Event/Rx bus的優缺點。並且提到了如何“正確”使用RxJava,而不是使用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
在 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
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吧。如果有興趣,可以直接閱讀
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 主要負責人的系列部落格(純英文,而且很難懂,不是英語難懂,是原理很難懂)。
關於lift
讀過扔物線大神文章入門的同學應該對lift
有一個瞭解。RxJava 1.x 幾乎所有操作符都是基於lift
完成的。但是RxJava 2.x 可以說幾乎看不到lift
。 目前lift
僅僅作為提供自定義操作符的一個介面(雖然更推薦使用簡單好用的compose
,因為lift
需要複寫七個抽象方法。)。
最後再說一下幾點:
- Flowable:Floawble其實在實現上和Observable類似,區別是Observable同過 Disposable控制取消訂閱。而Flowable同過Subscription。其中還需要request()方法控制流量。具體關於這個問題,我推薦這篇文章
總結:
- 我們從原始碼分析角度來說,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。