大話RxJava:二、輕鬆學原始碼之基礎篇

iamxiarui_發表於2018-07-02

##寫在前面

前篇文章簡單介紹了一下RxJava的概念與基本使用,本來準備繼續說一下RxJava的進階使用,包括一些複雜操作符的使用與執行緒控制的相關內容。然後想了想,不能這樣急躁地去學如何使用,應該先稍微明白它的一些過程,後面學習起來思路更加清晰,這也是我之前學習RxJava的一個誤區所在。

所以今天這篇文章,打算先認識一下基本的常見的兩種操作符及其使用,然後採用圖文的模式詳細介紹一下RxJava的基礎原始碼,主要包括create()與subscribe()這兩個方法到底做了什麼事情。

有了這兩個基礎後,後期學大量複雜且重要的操作符及其原理就有了基本的認知,至少學到複雜的地方不慌。而採用圖文模式講解原始碼看起來也不煩躁,輕輕鬆鬆得去學習。

下面是本文的目錄:

  • 寫在前面
  • 初識操作符
    • Observable.just()
    • Observable.from()
  • 基礎原始碼
    • create()
    • subscribe()
  • 結語
    • 參考資料
    • 專案原始碼

##初識操作符

所謂操作符(Operators),簡單來說就是一種指令,表示需要執行什麼樣的操作。Rx中的每種程式語言實現都實現了一組操作符的集合。RxJava也不例外。

RxJava中有大量的操作符,比如建立操作符、變換操作符、過濾操作符等等,這些操作符要全部講解完幾乎是不可能也沒必要的事情。所以我們只介紹常見的、有用的、重要的操作符。其他的如果用到直接到文件查詢就行了。

下面就針對前篇文章的建立(create)來說明一下另外兩種常見的建立操作符。先來回顧一下create()操作符,比較簡單,這裡就不解釋了:

//建立Observable
Observable.create(new Observable.OnSubscribe<String>() {
	@Override
	public void call(Subscriber<? super String> subscriber) {
		subscriber.onNext("Hello");
		subscriber.onNext("World");
		subscriber.onCompleted();
	}
	}).subscribe(new Observer<String>() {
	
		@Override
		public void onNext(String s) {
			Log.i("onNext ---> ", s);
		}
		
		 @Override
		public void onCompleted() {
			Log.i("onCompleted ---> ", "完成");
		}
		
		@Override
		public void onError(Throwable e) {
		
		}
});
複製程式碼

###Observable.just()

首先給出定義:

Just操作符是建立一個將引數依次傳送出來的Observable

具體一點來說就是, just() 中會接收1~9個引數,它會返回一個按照傳入引數的順序依次傳送這些引數的Observable。

這樣說可能還是不夠清晰,所以畫個圖來看:

just流程圖

從圖中可以看出,其實就是依次傳送單個資料,它的具體寫法是這樣的,非常簡單:

Observable.just("Hello","world");
//其實就相當於依次呼叫:
//subscriber.onNext("Hello");
//subscriber.onNext("World");
複製程式碼

但是這裡要注意一點,如果你傳遞null給just,它會返回一個傳送null值的Observable,而不是返回一個空Observable(完全不傳送任何資料的Observable)。後面會講到,如果需要空Observable應該使用 Empty 操作符。

現在來看完整的程式碼,程式碼本身很簡單,注意看Log日誌:

//建立Observable
Observable.just("Hello", "World", null)
	.subscribe(new Observer<String>() {

		@Override
		public void onNext(String s) {
			if (s == null) {
				Log.i("onNext ---> ", "null");
			}else {
            	Log.i("onNext ---> ", s);
			}
		}

		@Override
		public void onCompleted() {
			Log.i("onCompleted ---> ", "完成");
		}

		@Override
		public void onError(Throwable e) {
			Log.i("onError ---> ", "出錯 --->" + e.toString());
		}
});
複製程式碼

Log

這裡因為我們要列印字串,所以不能為null,我就處理了一下,可以看到當傳送 null 的時候,s確實等於null。

###Observable.from()

儘管與just一樣是建立操作符,但是from操作符稍微強大點。因為from操作符的作用是:

將傳入的陣列或 Iterable 拆分成具體物件後,依次傳送出來。

注意,這裡不再是傳送單個物件,而是直接傳送一組物件。為了與just對比,也來畫個圖描述一下:

from流程圖

它的具體寫法是這樣的,也非常簡單:

String[] str = new String[]{"Hello", "World"};
//建立Observable
Observable.from(str);
複製程式碼

這裡由於篇幅關係,我就不貼完整程式碼了,跟just是類似的,十分簡單。

##基礎原始碼

講了兩個簡單但是常用的操作符後,我們回過頭來看一下之前的實現RxJava的程式碼,這裡我打上了Log日誌,來看一下每個方法執行的順序。

//建立Observable
Observable.create(new Observable.OnSubscribe<String>() {
	@Override
	public void call(Subscriber<? super String> subscriber) {
		subscriber.onNext("Hello");
		subscriber.onNext("World");
		subscriber.onCompleted();
		Log.i("執行順序 ---> ", " call ");
	}
	}).subscribe(new Observer<String>() {

	@Override
	public void onNext(String s) {
		Log.i("onNext ---> ", s);
		Log.i("執行順序 ---> ", " subscribe onNext");
	}
	
	@Override
	public void onCompleted() {
		Log.i("onCompleted ---> ", "完成");
		Log.i("執行順序 ---> ", " subscribe onCompleted");
	}
	
	@Override
	public void onError(Throwable e) {
		Log.i("onError ---> ", "出錯 --->" + e.toString());
	}
});
複製程式碼

好了,來看一下Log日誌:

執行順序Log

從圖中可以看到,subscribe方法先執行,等執行完成後再執行call方法。

好了,這就是結論。先在腦子裡產生個印象,方便後面追溯。

###create()

先來看看Observable的create()方法做了些什麼?Ctrl點進去看看:

public static <T> Observable<T> create(OnSubscribe<T> f) {
    return new Observable<T>(hook.onCreate(f));
}
複製程式碼

啥事沒幹,就是返回一個 Observable

再看看它的建構函式,構造一下物件:

protected Observable(OnSubscribe<T> f) {
    this.onSubscribe = f;
}
複製程式碼

再來看這個 hook.onCreate(f)hook 是啥呢?

hook是一個代理物件, 僅僅用作除錯的時候可以插入一些測試程式碼。

static final RxJavaObservableExecutionHook hook = RxJavaPlugins.getInstance().getObservableExecutionHook();
複製程式碼

注意是僅僅,所以它幾乎沒啥用處,完全可以忽略。來看 hook.onCreate(f)

public <T> OnSubscribe<T> onCreate(OnSubscribe<T> f) {
    return f;
}
複製程式碼

依然啥事沒幹,只是把 OnSubscribe 這個物件返回了一下。

OK,說到這裡,雖然我一直在強調它“啥事沒幹”,其實仔細推敲,它還真做了三件事情:

  • 返回了一個Observable(假設為ObservableA)
  • 返回了一個OnSubscribe(假設為OnSubscribeA)
  • 把返回的OnSubscribe在Observable建構函式中儲存為Observable的 .onSubscribe 屬性

說到這裡,不知道大家看懂了沒有。我第一次看這到這裡的時候,還有略微有點模糊的,沒關係,只要模糊那就畫圖理解:

create流程圖

這樣看起來是不是輕鬆很多,create()就做了這樣簡單的事情,所以概括(但可能並不準確)地來說就是:

create()方法建立了一個Observable,且在這個Observable中有個OnSubscribe。

所以就畫個簡圖就如下圖所示這樣,這個圖要注意,之後還會擴充套件:

create簡圖

好了,create方法就分析到這裡,雖然有點囉嗦,但是已經十分詳細了。

###subscribe()

現在來看另外一個比較重要的操作 subscribe() ,在前篇文章中說過,這個是將觀察者(Observer)與被觀察者(Observable)聯絡到一起的操作,也就是產生一種訂閱(Subcribe)關係。

跟前面的一樣,先來看一下原始碼,點進去是這樣的:

public final Subscription subscribe(final Observer<? super T> observer) {
    if (observer instanceof Subscriber) {
        return subscribe((Subscriber<? super T>)observer);
    }
    return subscribe(new ObserverSubscriber<T>(observer));
}
複製程式碼

之前我們說過一句話:

實質上,在 RxJava 的 subscribe 過程中,Observer 也總是會先被轉換成一個 Subscriber 再使用。

在這裡就能夠看出,首先 if 中的語句意思是如果這個Observer已經是Subscriber型別,那就直接返回。如果不是的話 new了一個ObserverSubscriber ,再點進去看看:

public final class ObserverSubscriber<T> extends Subscriber<T> {
    final Observer<? super T> observer;

    public ObserverSubscriber(Observer<? super T> observer) {
        this.observer = observer;
    }
    
    @Override
    public void onNext(T t) {
        observer.onNext(t);
    }
    
    @Override
    public void onError(Throwable e) {
        observer.onError(e);
    }
    
    @Override
    public void onCompleted() {
        observer.onCompleted();
    }
}
複製程式碼

果然,它還是轉成了Subscriber型別,剛好印證了之前的話。所以為了方便起見,之後文章中,所有的觀察者(Observer)我都用Subscriber來代替。 這是一個小插曲,注意一下就好。

好了,繼續看 subscribe 原始碼:

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

private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
    ...	
    hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
	...
}
複製程式碼

把一些暫時無關的程式碼省略掉來看,其實就是執行了一句 hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);

而這個 hook.onSubscribeStart 方法再點進去看看:

public <T> OnSubscribe<T> onSubscribeStart(Observable<? extends T> observableInstance, final OnSubscribe<T> onSubscribe) {
        // pass through by default
        return onSubscribe;
    }
複製程式碼

可以看到,竟然直接返回了一個 onSubscribe ,由於之前說過這個hook沒什麼作用,直接刪掉,那就等於整個 subscribe 做了一件事就是 onSubscribe.call(subscriber) ,當然這個call裡面的引數subscriber是我們程式碼中傳遞進去的。

而onSubscribe在create原始碼解析中我們已經知道是新建 ObservableA 的一個屬性,所以總結來說,subscribe()方法做的事情就是這樣:

ObservableA.onSubscribe.call(subscriber);

而呼叫 call 方法,就是呼叫傳入的引數subscriber的onNext/onCompleted/onError方法。

這就是全部的過程。

看到這裡,估計大家又迷糊了。沒關係,依然畫個圖來說,圖中省略了create中的建立步驟:

全過程

結合圖我們最後再順一下思路:

  • 首先建立過程也就是create()方法中建立了一個Observable,並有一個onSubscribe屬性;
  • 其次在訂閱過程也就是subscribe()方法中,呼叫了create()方法中建立的Observable的onSubscribe屬性的call方法;
  • 最後這個call回撥的就是程式碼中建立的Subscriber的onNext/onCompleted/onError方法。

不知道大家還記得那個Log日誌麼,從日誌可以看到,將onNext與onCompleted方法執行完後,call方法才結束。這也印證了call方法回撥Subscriber的方法這一說。

##結語

好了,終於把原始碼中比較簡單的部分講解完了,等於是再複習了一邊之前學的。

而且終於也把RxJava的入門知識講解完了。後面的文章中,就開始學如何稍微高階一點的運用RxJava,比如map/flatmap操作符、lift的原理、執行緒控制的原理、各種運用場景等等,還有很長的路要走啊。

最後這是我第一次試著講解原始碼,而且也在邊學邊分享,所以肯定有錯誤或不清楚的地方,歡迎大家指正與交流。

###參考資料

RxJava基本流程和lift原始碼分析

徹底搞懂 RxJava — 基礎篇

###專案原始碼

IamXiaRui-Github-FirstRxJavaDemo


個人部落格:www.iamxiarui.com

原文連結:www.iamxiarui.com/?p=760

相關文章