RxJava學(xué)習(xí)筆記(一)事件分發(fā)介紹和源碼分析

對于Rxjava想必大家都很熟悉了,這里不再贅述什么是Rxjava。

今天的主題是:從源碼角度(2.0)分析,Rxjava是如何做到事件分發(fā)的??


以下是今天學(xué)習(xí)筆記的目錄:

  • 關(guān)鍵類及方法簡要說明
  • 分析源碼,查看事件是如何傳遞的

關(guān)鍵類及方法說明

首先我們知道Rxjava是一個(gè)擴(kuò)展的“觀察者”模式,既然是“觀察者”模式,那么不可避免的會(huì)涉及到:被觀察者,觀察者,訂閱操作,事件。那么Rxjava中哪些類是這些身份的扮演者呢?先上一下基本類圖

類圖:

image

基本使用code:

image

結(jié)合圖-1和圖2,我們可以知道"被觀察者"以及"觀察者"是誰了。 那"ObservableOnSubscribe","ObservableEmitter","Disposable"又是什么? 接下來我們就從"Observer"開始逐一梳理下他們是什么,以及如何工作的。

Observer:觀察者
image
image

從上圖中我們可以知道 “Observer” 是Rxjava 中 觀察者的身份。我們簡單介紹下Observer中各個(gè)方法的作用。

onSubscribe(Disposable d):

1:當(dāng) Observable向 Observer發(fā)送事件前,調(diào)用此方法(具體在哪調(diào)用的,后續(xù)會(huì)分
析到,這里先給出結(jié)論)。
2:可以調(diào)用 Disposable(為了便于理解,我們可以把它想象成 “消息控制開關(guān)”,因?yàn)樗拖裎覀兤匠=佑|的各種開關(guān)一樣,來控制消息是否分發(fā)給 Observer)的dispose()來告知 Observable,當(dāng)前的 Observer是否需要接受事件。

onNext(T value):

1:該方法就是 Observable傳遞訂閱事件給Observer的回調(diào)方法,其中value就是 Observer向Observable訂閱的要監(jiān)聽的事件。
2:如方法注釋所說的那樣,該方法可以調(diào)用多次(想想也是,觀察者訂閱的事件當(dāng)然可能發(fā)生多次了)。
3:當(dāng)調(diào)用onComplete()/onError()之后就算再調(diào)用onNext()事件也不會(huì)發(fā)送至 Observer。

onComplete():

1:該方法標(biāo)記之后的任何事件將不會(huì)發(fā)送給 Observer
2:當(dāng)調(diào)用了onComplete()之后再調(diào)用onError()事件是不會(huì)發(fā)送給 Observer。

onError(Throwable e):

1:該方法通知觀察者出現(xiàn)了錯(cuò)誤情況。
2:當(dāng)調(diào)用了onError()之后,再調(diào)用onNext()/onComplete()事件也不會(huì)發(fā)送給 Observer。

問題:
1:在實(shí)際應(yīng)用時(shí)發(fā)現(xiàn),“當(dāng)調(diào)用onComplete()之后再調(diào)用onError() app會(huì)拋出異常并crash”。
2:當(dāng)設(shè)置 observeOn(Scheduler s)之后,會(huì)導(dǎo)致 “onError()之前的事件接受不到或者丟失部分事件”。
以上兩個(gè)問題會(huì)在稍后給出原因。

Observable:被觀察者

首先,我們知道它是Rxjava中 “被觀察者” 的具體實(shí)現(xiàn)。 其次,我們要?jiǎng)?chuàng)建一個(gè)被觀察者可以通過Observable提供的N多靜態(tài)方法"去new一個(gè)出來"。我們拿"create()"舉個(gè)例子。

create():

image
image
image

create()方法其實(shí)做的事情并不多。

  • 判斷傳入的ObservableOnSubscribe是否為null。
  • 創(chuàng)建ObservableCreate(該類繼承Observable)并把ObservableOnSubscribe添加到 ObservableCreate,并返回ObservableCreate。

既然創(chuàng)建好了 被觀察者,那么接下來就需要 "觀察者 訂閱 被觀察者,讓被觀察者時(shí)刻保持警惕,當(dāng)有我要的事件發(fā)生時(shí),記得通知我",那"訂閱"這個(gè)動(dòng)作 Rxjava是如何實(shí)現(xiàn)的呢?

subscribe():訂閱操作

我們都知道 標(biāo)準(zhǔn)觀察者模式中,實(shí)現(xiàn)"訂閱"操作的話應(yīng)該是 "觀察者.訂閱(被觀察者)"這種寫法才對,就拿給View設(shè)置點(diǎn)擊事件來說應(yīng)該是"View.setOnClickListener()"這種。那為啥Rxjava中要反其道而行要采用"被觀察者.訂閱(觀察者)"這種方式呢? 這是因?yàn)镽xjava采用了“流式api”調(diào)用策略,這樣寫可以使代碼更簡潔,有種一氣呵成的感覺,所以就把 "訂閱"動(dòng)作放到了Observable中。廢話不多說,我們來看下subscribe()都做了些什么事情吧。

image
image

首先,通過ObjectHelper.requireNonNull()判斷傳入的Observer是否為null。
其次,調(diào)用RxJavaPlugins.onSubscribe()返回當(dāng)前Observer(具體該方法會(huì)在后續(xù)章節(jié)分析)。
再次,調(diào)用ObjectHelper.requireNonNull()判斷傳入的Observer是否為null。
最后,調(diào)用subscribeActual()進(jìn)行 訂閱操作。

subscribeActual():

通過該方法的解釋,我們可以知道此方法是 "實(shí)際訂閱動(dòng)作的發(fā)生地"。

到此“觀察者模式”中的三大主角,“觀察者”和“被觀察者”以及“訂閱操作”就簡單介紹完了。那么問題來了,接下來“事件”需要怎么發(fā)出呢?好,我們繼續(xù)往下看。

事件:

ObservableOnSubscribe:

image

首先從該接口的定義中我們知道,此接口是 “事件產(chǎn)生和推送的地方”。具體的事件的產(chǎn)生和發(fā)送是在subscribe()中實(shí)現(xiàn)的。我們來舉個(gè)例子,聲情并茂的說明下吧。 我們大都玩過cs,cf之類的射擊游戲,假如我是警,對面人物是匪,此時(shí)我們相遇了(我沒看到他),一根無形的線把我們“栓”在了一起。此時(shí)對面哥們一看,有敵人,二話不說舉槍就開始射擊,不過還好我穿了防彈衣,再加上反映比較快馬上就找好了掩體進(jìn)行了反擊。
對于這樣一個(gè)場景來說,假如我是Observer,那么對面那哥們就是Observable,那根“無形的線”就可以理解為subscribe動(dòng)作,槍對于我們來說就是“事件的產(chǎn)生者或者容器”那么“子彈”可以理解為具體要發(fā)送的“事件”了。
這里的“槍”指的就是“ObservableOnSubscribe”。


ObservableEmitter:

繼續(xù)沿用上邊的例子,我們說到了可以用“槍”來比喻成“ObservableOnSubscribe”來理解它的定義。那么,槍要想發(fā)射子彈的話,人得扣動(dòng)扳機(jī)才行,對吧,那我們就可以把“ObservableEmitter”理解成“槍的扳機(jī)”,用于控制事件的“發(fā)射”。
看一下類圖吧。

image
image

通過類圖我們不難發(fā)現(xiàn),ObservableEmitter實(shí)現(xiàn)了Emitter接口,Emitter接口中定義了onNext(),onError(),onComplete()等三個(gè)方法,是不是感覺在哪見過?沒錯(cuò),這三個(gè)方法正好對應(yīng)的是Observer中的onNext(),onError(),onComplete()。通過Emitter調(diào)用這三個(gè)方法,則會(huì)分別回調(diào)Observer對應(yīng)的方法(具體實(shí)現(xiàn)我們在稍后會(huì)給出)。那么調(diào)用Emitter的三個(gè)方法后Observer會(huì)收到消息,事件不就是從 被觀察者向觀察者傳遞了嗎?


Disposable

最后再來說一說,Disposable,老規(guī)矩,上圖。

image

我們可以把"Disposable"理解為“消息控制開關(guān)”,就像電燈的開關(guān)一樣,它控制了是否消息可以送達(dá)至Observer處。
而且細(xì)心的同學(xué)觀察 圖-2以及Observer接口的定義代碼可以發(fā)現(xiàn),Observer的onSubscribe(Disposable d)把該開關(guān)返回給了 Observer,為什么要這么設(shè)計(jì)呢?
原因應(yīng)該有2個(gè):
1:當(dāng)消息發(fā)送前,首先回調(diào)Observer的onSubscribe()告知觀察者我要開始給你發(fā)消息了,你先做做準(zhǔn)備,這樣的 話我們可以在第一條消息未發(fā)送之前在該方法中做一下準(zhǔn)備工作之類的。
2:再調(diào)該方法時(shí),如果觀察者不想被觀察者發(fā)送事件,可能我還沒做好準(zhǔn)備,或者我改變注意我不想接收 被觀察的發(fā)送的事件了,可以調(diào)用Disposable 的dispose(),這樣當(dāng) 被觀察發(fā)送事件的時(shí)候,就會(huì)判斷,觀察者是不是需要我的事件,如果不需要我就不發(fā)了(實(shí)際代碼內(nèi)部也是這樣處理的,看過源碼的東西大概都清楚這些事,這里就稍微介紹一下)。

簡單介紹就到這里了,接下來我們就從源碼角度來看看,事件是怎樣從 Disposable 傳遞到 Observer的。


源碼分析

看過Rxjava源碼的同學(xué)都知道,Rxjava的代碼量還是挺多的,我們不可能事無巨細(xì)。那么如何閱讀其中的代碼比較好呢?我覺得應(yīng)該遵從這樣一個(gè)原則:掌握大方向,梳理脈絡(luò)。細(xì)化小方面,深入理解。
首先,我們需要了解這個(gè)功能,是怎樣是實(shí)現(xiàn)的,用到了哪些類,接口等,最好列出來,畫一畫類圖,流程圖,要做到心中有數(shù),不要過分追究細(xì)節(jié),只要知道這個(gè)功能的每一步對應(yīng)的是哪些類就行了。
最后,當(dāng)上步我們完成之后,就可以對存在疑慮的地方做進(jìn)一步研究,比如某個(gè)知識(shí)點(diǎn)可能不大清楚,這時(shí)就需要花事件和心思搞明白了。如此這般流程走下來,我相信閱讀源碼并不只是枯燥乏味的事情,這其中定會(huì)充斥著很多歡樂。廢話不多說了,接下來我們就開始閱讀源碼吧。

大方向:

Observable創(chuàng)建:

“關(guān)鍵類及方法說明”我們從create()方法入手簡要分析了下Observable是如何創(chuàng)建的。通過代碼我們知道,create()方法最終創(chuàng)建了一個(gè)名為“ObservableCreate”的Observable,并把“ObservableOnSubscribe”存儲(chǔ)到ObservableCreate中。

Observer創(chuàng)建:

Observer的創(chuàng)建也可以參考“關(guān)鍵類及方法說明”中關(guān)于Observer的介紹,這里不再說了。

接下來我們主要看一下,執(zhí)行“訂閱”操作之后事件是如何傳遞的。

事件的傳遞:

通過“關(guān)鍵類及方法說明”中關(guān)于subscribe()發(fā)生后的介紹,我們知道“實(shí)際訂閱”操作都是發(fā)生在subscribeActual()該方法中的,又因?yàn)樵摲椒ㄊ浅橄蠓椒ǎ晕覀冎苯舆M(jìn)入“ObservableCreate”類查看其對subscribeActual()方法的實(shí)現(xiàn)吧。

image

這是ObservableCreate中subscribeActual()方法的具體實(shí)現(xiàn)。接下來我們具體分析下。

1:創(chuàng)建CreateEmitter
image

“關(guān)鍵類及方法說明”中我們介紹了什么是“ObservableEmitter”,這里不再贅述。閱讀源碼我們發(fā)現(xiàn),通過調(diào)用CreateEmitter的構(gòu)造方法,把“Observer”對象保存至到了CreateEmitter中問題:為什么此Emitter中要保留一份外部Observer的引用呢? 稍后我們給出原因。

2:回調(diào)Observer的onSubscribe(Disposable d)

因?yàn)镃reateEmitter也實(shí)現(xiàn)了Disposable,所以就可以把CreateEmitter回調(diào)給 Observer了。此時(shí)觀察者就可以在onSubscribe()中做一些事件發(fā)送前的準(zhǔn)備工作什么的。

3:發(fā)送事件

首先,回調(diào)ObservableOnSubscribe的subscribe()并把新創(chuàng)建的CreateEmitter返回去。此時(shí)我們就可以用該Emitter發(fā)送事件了(這就是Observable產(chǎn)生以及發(fā)送事件的地方)。例如:

image
3.1:OnNext()
image

首先,判斷傳遞的“事件”是否為null。
其次,再調(diào)用“isDisposed()”判斷“消息開關(guān)”是否已經(jīng)關(guān)閉了(這個(gè)稍后分析)。
最后,如果沒關(guān)閉,則回調(diào)Observer的onNext()方法回調(diào)事件。還記在分析ObservableEmitter時(shí)引入的那個(gè)問題嗎?在此,就知道原因了吧。如果不給我一個(gè)觀察者的引用,我把事件回調(diào)給誰呢,是吧。

3.2:onComplete()
image

首先,調(diào)用“isDisposed()”判斷“消息開關(guān)”是否已經(jīng)關(guān)閉了,如果沒關(guān)閉和繼續(xù)。
其次,調(diào)用Observer的onComplete()回調(diào)Complete事件。
最后,調(diào)用dispose()關(guān)閉“消息控制開關(guān)”。

3.3:onError()
image

首先,判斷傳入的Throwable是否為null。
其次,調(diào)用“isDisposed()”判斷“消息開關(guān)”是否已經(jīng)關(guān)閉了,如果沒關(guān)閉和繼續(xù)。如果已經(jīng)關(guān)閉了,則調(diào)用RxJavaPlugins.onError(t),該方法稍后再解釋
最后,調(diào)用Observer的onError()回調(diào)error事件。


小方面

自此我們結(jié)合源碼,大體捋清楚了,Rxjava中事件傳遞的一個(gè)過程,這就是前邊提到的“掌握大方向,梳理脈絡(luò)”。接下來我們對前面遺留的諸多問題進(jìn)行一一深入理解,這部分也就是“細(xì)化小方面,深入理解”。

首先我們在創(chuàng)建CreateEmitter的時(shí)候,發(fā)現(xiàn),它既實(shí)現(xiàn)了Emitter接口,又實(shí)現(xiàn)了Disposable接口,所以說它既是“消息發(fā)射器”又是“消息控制開關(guān)”。而且我們在分析onNext(),onComplete(),onError()方法時(shí)都發(fā)現(xiàn),這些方法內(nèi)部都先調(diào)用了"isDisposed()"判斷“消息開關(guān)”是否關(guān)閉了,接下來我們就從“消息發(fā)射器”角度來捋一捋這個(gè)方法是怎么實(shí)現(xiàn)的。

isDisposed()

image
image
image
image

我們知道CreateEmitter是繼承自AtomicReference(這是專門采用原子操作,進(jìn)行更新操作對象的一個(gè)原子類)。 首先,通過get()獲取AtomicReference中的value的值,默認(rèn)值為null。 其次,調(diào)用DisposableHelper的isDisposed()把get()獲取的值傳入,并與DisposableHelper.DISPOSED進(jìn)行比較,判斷不是DisposableHelper.DISPOSED則返回false,如果是的話則返回true。

setDisposable()

做為“消息發(fā)射器”CreateEmitter還必須實(shí)現(xiàn)此方法,我們看看一下這個(gè)方法都干了些什么吧。

image
image
image

1:把CreateEmitter的當(dāng)前實(shí)例和Disposable傳入RxJavaPlugins的set()方法中。
2:CreateEmitter做為AtomicReference,獲取當(dāng)前CreateEmitter的value并賦值給“current”。
2.1:如果 “current ==DISPOSED”,且傳入的Disposed不為null,則調(diào)用傳入的Disposable的dispose()并跳出當(dāng)前方法。
2.2:如果 “current !=DISPOSED”,執(zhí)行AtomicReference的compareAndSet() 給 CreateEmitter的value 設(shè)置為傳入的Disposable。如果current不為null的話,執(zhí)行dispose()方法。

至此我們發(fā)現(xiàn)setDisposable()就是把傳入的“Disposable”保存起來,等到調(diào)用“isDisposed等方法”來判斷“消息開關(guān)是否關(guān)閉了”。 接下來我們做個(gè)“猜想”: **如果在消息發(fā)送前設(shè)置Disposable為DisposableHelper.DISPOSED的話,消息是會(huì)繼續(xù)傳遞的,如果設(shè)置的是自定義的Disposable的話,消息則不會(huì)被傳遞。 ** 下面我們就實(shí)際測試下,這個(gè)“猜想”是否成立吧。

case1:在ObservableOnSubscribe的subscribe()中設(shè)置Disposable為DisposableHelper的唯一實(shí)例。

image

log信息為下圖。

image

case2:在ObservableOnSubscribe的subscribe()中設(shè)置Disposable為自定義的Dispaseable。

image
image

根據(jù)以上測試結(jié)果確實(shí)和我們的“猜想”一致為什么呢?此時(shí)我們回過頭來看看上邊關(guān)于** isDisposed() 以及 onComplete()的分析,發(fā)現(xiàn) 當(dāng)繼續(xù)執(zhí)行CreateEmitter的onComplete時(shí),此時(shí)的Dispaseable如果為DisposableHelper的DISPOSED實(shí)例,isDisposed() 就會(huì)返回true,所以 后續(xù)的Complate會(huì)回傳給Observer了。如果為false,當(dāng)然就不會(huì)走了唄。**


CreateEmitter做為“消息發(fā)射器”的角色的責(zé)任分析完畢后,接下來我們分析下其做為“消息開關(guān)”又能干些什么吧。

當(dāng)CreateEmitter做為“消息開關(guān)”時(shí),它自身有兩個(gè)方法需要實(shí)現(xiàn),它們分別是:isDisposed()和dispose()。isDisposed()以及分析過了,接下來只需要分析下dispose()就行了。

dispose():

image
image
image

通過閱讀源碼我們知道,當(dāng)CreateEmitter中的value對應(yīng)的不是DisposableHelper的DISPOSED實(shí)例的話,就會(huì)把DisposableHelper的DISPOSED保存至CreateEmitter中。當(dāng)通過Emitter發(fā)送事件時(shí),就會(huì)先調(diào)用isDisposed()來判斷“消息開關(guān)”是否關(guān)閉了,如果關(guān)閉了,則中斷事件的傳遞。


到此RxJava的關(guān)于事件分發(fā)這塊到底是如何做的已經(jīng)分析完了,如果大家看完感覺有幫助的話歡迎點(diǎn)擊收藏和喜歡。如果有錯(cuò)誤之處,還望各位指出,我會(huì)盡快改正的。后續(xù)我會(huì)繼續(xù)分享關(guān)于,線程調(diào)度,常用操作符以及2.0關(guān)于背壓這3個(gè)方面的介紹,謝謝大家。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 簡單是否真的簡單 簡單有時(shí)候其實(shí)也很簡單,像圖中的孩子,一顆小小的蒲公英就能找到屬于自己歡樂。這是小時(shí)候的我們...
    農(nóng)村奮斗的青年閱讀 327評論 1 1
  • 我認(rèn)為把握這個(gè)度的關(guān)鍵點(diǎn)在于要對所做的事情要有一個(gè)清楚的認(rèn)識(shí)和目標(biāo)。這是什么意思呢,我解釋一下。 比如這件事對你的...
    du_xzhe閱讀 91評論 0 0
  • (十二)月華轉(zhuǎn)過臉去,看著一身黑衣的巫師一步一步朝自己走來,盡管自己活了四五十個(gè)年頭,還是被巫師的黑色光環(huán)吸引了,...
    阿修落落閱讀 259評論 0 0