RxJava如何結合觀察者與鏈式處理

Dorae發表於2019-01-14

RxJava如何結合觀察者與鏈式處理

Author: Dorae
Date: 2018年12月3日17:10:31 轉載請註明出處


一、概述

首先問自己幾個問題,如果非常清楚這幾個問題的目的與答案,那麼恭喜你,不用繼續往下看了-_-。

  1. RxJava是幹什麼的;
  2. 鏈式呼叫中當存在數個Observable.subscribeOn()時的處理方式;
  3. 鏈式呼叫中當存在數個Observable.observeOn()時的處理方式;
  4. 資料是如何經過操作符進行的處理。

回顧

觀察者模式

如圖1-1所示

RxJava如何結合觀察者與鏈式處理
圖 1-1

Java8的stream

參見這裡

二、RxJava是什麼

一款為了簡化非同步呼叫,且功能比較全面的框架。

三、RxJava如何結合了觀察者模式與鏈式處理

參見Java8中的sink鏈,在RxJava中同樣實現了鏈式處理。如程式碼片段code1-1所示,我們對其結構進行分析:

code1-1

Observable.create(new ObservableOnSubscribe<String>() {

		@Override
		public void subscribe(ObservableEmitter<String> emitter) throws Exception {
			emitter.onNext("Dorae");
		}
	})
	.filter(e -> e.contains("o"))
	.map(e -> "AfterMap: " + e)
	.filter(e -> e.contains("D"))
	.subscribe(new Observer<String>() {

				@Override
				public void onNext(@NonNull String o) {
					System.out.println("觀察者 onNext: " + o);
				}

				@Override
				public void onSubscribe(Disposable d) {
					System.out.println("觀察者onSubscribe: " + d + "### " + Thread.currentThread().getName());
				}

				@Override
				public void onError(Throwable e) {
				}

				@Override
				public void onComplete() {

				}
			});
複製程式碼

1、首先看下其輸出結果:

觀察者onSubscribe: io.reactivex.internal.operators.observable.ObservableFilter$FilterObserver@52d455b8### main

觀察者 onNext: AfterMap: Dorae

2、現在來對如何輸出這段結果進行分析

首先了解下RxJava中的幾種基本角色:

  • Observable,是RxJava描述的事件流,可以說其與Observer構成了RxJava的基礎。在鏈式呼叫中,事件從建立到加工到最後被Observer接受,其實就是由一條Observerable鏈串起來的。
  • Observer,RxJava中的訂閱者,也就是需要對事件進行響應的一個角色。其實除了我們通常自己實現的一個Observer,在鏈中的每一步都會產生一個Observer,然後這些Observer構成一條鏈,最終完成整個鏈的計算。
  • ObservableOnSubscribe,整個事件流的源頭,通常需要我們自己實現,其依賴一個Emitter。
  • Emitter,可以將其理解為觸發器,推動整個流程的運轉。
  • Scheduler,這個其實不用太過關心,RxJava用其封裝了Thread,用於完成執行緒切換等任務。

是不是感覺上邊的一堆廢話非常枯燥?先上一張RxJava的核心結構,如圖3-1所示。

RxJava如何結合觀察者與鏈式處理
圖 3-1

現在我們再來看看code1-1,其最終形成的Observable鏈如圖3-2所示,每次呼叫map、filter等操作,都會生成一個新物件,並且保持了一個對上游的引用(用於生成Observer鏈)。

RxJava如何結合觀察者與鏈式處理
圖 3-2

Observer鏈如圖3-3所示,整個事件流程由CreateEmitter觸發,最終交由我們的實現Observer$1處理。

RxJava如何結合觀察者與鏈式處理
圖 3-3

看了上邊幾張圖之後,是不是感覺清晰了很多?那麼讓我們進一步看下Rxjava如何完成了一鍵執行緒切換。

四、RxJava如何實現執行緒切換

通常我們使用RxJava的執行緒切換功能時,只需要在呼叫鏈中加上一句subscribeOn()或observeOn(),其中Scheduler如上所述,其實就是一個包裝了ThreadPool的排程器。那麼我們先來看下相關原始碼。

1、subscribeOn

如程式碼code4-1所示,為subscribeOn的核心程式碼。很明顯,其中在新執行緒中只是簡單的直接呼叫了source,也就是說這裡之後的所有操作均在一個新執行緒中進行,和單執行緒並沒有什麼區別。

code 4-1

public final Observable<T> subscribeOn(Scheduler scheduler) {
	return new ObservableSubscribeOn<T>() {
		@Override
		public void subscribeActual(final Observer<? super T> observer) {
			scheduler.createWorker().schedule(new SubscribeTask() {
				@Override
				public void run() {
					source.subscribe(e);
				}
			});
		}
	};
}
複製程式碼

2、observeOn

如程式碼段code4-2所示,為observeOn的核心邏輯,可以看出其在訂閱階段(生成Observer鏈的階段)還是在當前執行緒執行,只有觸發之後,到了ObserverOn的Observer的節點時才會真正的切換到新執行緒。

code 4-2

public final Observable<T> observeOn(Scheduler scheduler) {
	return new ObservableOnSubscribe<T>() {
		@Override
		public void subscribeActual(@NonNull Observer<Object> e) { 
			source.subscribe(new Observer<T>() {

				@Override
				public void onNext(T var1) {
					scheduler.createWorker().schedule(new Runnable() {
						@Override
						public void run() {
							e.onNext(var1);
						}
					});
				}
			});
		}
	};
}
複製程式碼

多次Observable.subscribeOn()、多次Observable.observeOn()會發生什麼

通過上述code4-1、code4-2的分析,是不是可以推斷出當多次subscribeOn時會發生什麼?沒錯,雖然每次subscribeOn都會產生一次執行緒切換,但是真正起作用的只有最開始的一次subscribeOn,也就相當於只在最初的位置呼叫了subscribeOn;對於observeOn也是類似,每次都會產生新執行緒,但是每次都會產生一定的影響,也就是每個執行緒都承擔了一部分工作。

小結

通過本文,我們可以簡要了解到RxJava的基本原理,但是對於其豐富的api還需要在實踐中進行磨合。但是,RxJava既然作為一個非同步框架,其必然有一定的侷限,比如其切換執行緒時無法阻塞當前執行緒(這種對於Android等需要渲染或者網路IO的需求來說非常適用),但是對於常見的服務端業務來說,還需要額外引入阻塞當前執行緒的操作(因為大部分的server程式碼還是單執行緒模型),倘若完全不用執行緒切換在服務端強行引入,可能會得不償失。個人更推薦Java8的CompletableFuture。

參考

理解RxJava(一)基本流程原始碼分析

RxJava基本原理分析

相關文章