RxJava基本原理與使用(二)

前言

上一篇我們了解了RxJava的介紹以及通過一個(gè)例子學(xué)習(xí)了RxJava的展現(xiàn)形式奶赔,相信大家現(xiàn)在已經(jīng)對(duì)RxJava有一個(gè)初步的印象與概念了栓票。本篇我們將更深入的學(xué)習(xí)RxJava的基本原理以及如何使用RxJava。

觀察者模式

上一篇有提到RxJava的核心便是擴(kuò)展的觀察者模式,我們先來學(xué)習(xí)一下觀察者模式。


事件:小明按下遙控器開關(guān),空調(diào)啟動(dòng)并開始吹風(fēng)了滚停。按下制冷按鍵,空調(diào)吹出的風(fēng)變?yōu)闆鲲L(fēng)粥惧。再按下3檔風(fēng)速按鍵键畴,空調(diào)吹的風(fēng)變大了。
  
在這個(gè)事件中,空調(diào)作為觀察者起惕,遙控器作為被觀察者涡贱,空調(diào)通過紅外線檢測(cè)遙控器傳來的信號(hào)并作出響應(yīng)。

通過上圖我們可以很清晰的看出遙控器作為事件的生產(chǎn)方主動(dòng)發(fā)起事件惹想,是事件的起點(diǎn)问词,而空調(diào)作為事件的處理方被動(dòng)接收事件做出響應(yīng),是事件的終點(diǎn)嘀粱。而在事件傳遞的過程中可對(duì)事件進(jìn)行過濾激挪,轉(zhuǎn)換,合并等操作锋叨,就像例子中制冷與加大風(fēng)速的效果垄分。
  
這個(gè)概念是RxJava中的核心,它是基于觀察者模式來組建自己的程序邏輯娃磺,遙控器就相當(dāng)于RxJava的被觀察者Observable薄湿,空調(diào)相當(dāng)于觀察者Observer,而對(duì)事件處理的一些操作相當(dāng)于各類操作符偷卧。不同的是RxJava中觀察者需要對(duì)被觀察者進(jìn)行訂閱豺瘤,這樣當(dāng)被觀察者發(fā)出事件時(shí),觀察者才會(huì)接收到事件進(jìn)行處理听诸。若未進(jìn)行訂閱炉奴,被觀察者是不會(huì)發(fā)出任何事件的。

使用

了解了觀察者模式蛇更,接下來動(dòng)起指尖嘗試下怎么使用RxJava。

創(chuàng)建被觀察者Observable

第一步:創(chuàng)建被觀察者Observable:

Observable<Object> observable = Observable.create(new Observable.OnSubscribe<Object>() {
    @Override
    public void call(Subscriber<? super Object> subscriber) {
        //被觀察者的數(shù)據(jù)操作更新
        for (int i = 0; i < 5; i++)
            subscriber.onNext("xulei" + i);
        }
        subscriber.onCompleted();
    }
});

通過Observable.create()方法創(chuàng)建并返回一個(gè)Observable對(duì)象赛糟,create()方法需要一個(gè)OnSubsribe對(duì)象作為參數(shù)傳入并執(zhí)行call()方法派任。此OnSubsribe對(duì)象繼承自Action1。

而在call()方法中可通過subscriber.onNext()進(jìn)行事件的發(fā)送璧南,subscriber.onCompleted()標(biāo)記為事件發(fā)送完畢掌逛。subscriber.onError()標(biāo)記為事件發(fā)送過程出現(xiàn)異常。

除create()方法創(chuàng)建Observable方式外司倚,還可以使用just()與from()等方式豆混,這個(gè)在之后的創(chuàng)建操作符文章中會(huì)有講解。

創(chuàng)建觀察者Observer

第二步:創(chuàng)建觀察者Observer:

Observer observer = new Observer() {
    @Override
    public void onCompleted() { //標(biāo)記事件發(fā)送完畢的回調(diào)
        Log.e("rx_test", "onCompleted");
    }
    @Override
    public void onError(Throwable e) { //事件發(fā)送過程出現(xiàn)異常的回調(diào)
        Log.e("rx_test", "onError");
    }
    @Override
    public void onNext(Object o) { //接收到發(fā)送事件的回調(diào)
        Log.e("rx_test", "onNext:" + o.toString());
    }
};

在以往普通的觀察者模式中动知,觀察者通常只提供一個(gè)update()的方法皿伺,而RxJava擴(kuò)展的觀察者模式中的觀察者提供onNext(Object o)onCompleted()盒粮,onError(Throwable e)三個(gè)方法鸵鸥,分別對(duì)應(yīng)被觀察者call()方法中重寫的subscriber.onNext()subscriber.onCompleted()subscriber.onError()方法妒穴。而onNext()方法就對(duì)應(yīng)普通觀察者模式中的update()方法宋税。

RxJava擴(kuò)展的觀察模式彌補(bǔ)了普通觀察者模式的不足:

  1. 當(dāng)事件發(fā)送完畢可以調(diào)用onCompleted()方法進(jìn)行標(biāo)示。
  2. 當(dāng)事件發(fā)送過程中出現(xiàn)異常會(huì)自動(dòng)觸發(fā)onError()方法讼油,也可進(jìn)行手動(dòng)調(diào)用杰赛。
  3. Observable支持鏈?zhǔn)骄幊蹋瑥亩苊饬嘶卣{(diào)嵌套的問題矮台,也簡(jiǎn)化了代碼乏屯。

訂閱

最后一步:被觀察者Observable訂閱觀察者Observer。

這里不同于普通觀察者模式嘿架,上一篇我們講了在RxJava擴(kuò)展觀察者模式中瓶珊,如果沒有觀察者,被觀察者是不會(huì)發(fā)出任何事件的耸彪。所以這里是被觀察者訂閱觀察者伞芹。

observable.subscribe(observer);

訂閱很簡(jiǎn)單,一行代碼搞定蝉娜。調(diào)用Observable的subscribe()方法唱较,傳入觀察者對(duì)象作為參數(shù),這樣被觀察者與觀察者就進(jìn)行了綁定召川。

簡(jiǎn)寫

RxJava可以使用鏈?zhǔn)骄幊蹋?/p>

Observable.create(new Observable.OnSubscribe<Object>() {
    @Override
    public void call(Subscriber<? super Object> subscriber) {
        //被觀察者的數(shù)據(jù)操作更新
        for (int i = 0; i < 5; i++) {
            subscriber.onNext("xulei" + i);
        }
        subscriber.onCompleted();
    }
}).subscribe(new Observer<Object>() {
    @Override
    public void onCompleted() {
        Log.e("rx_test", "onCompleted");
    }
    @Override
    public void onError(Throwable e) {
        Log.e("rx_test", "onError");
    }
    @Override
    public void onNext(Object o) {
        Log.e("rx_test", "onNext:" + o.toString());
    }
});

邏輯梳理

到此一個(gè)RxJava的簡(jiǎn)單調(diào)用就實(shí)現(xiàn)了南缓,相信不少碼友看完之后還是很懵13,那我們?cè)賮硎崂硪幌抡麄€(gè)流程荧呐。首先使用Observable.create()創(chuàng)建了一個(gè)Observable<Integer>汉形,并在create()方法中傳入了一個(gè)OnSubscribe對(duì)象作為參數(shù),重寫OnSubscribe中的call()方法倍阐,當(dāng)Observable進(jìn)行訂閱后就會(huì)自動(dòng)觸發(fā)call()方法發(fā)送事件概疆。

注意:call()方法中的subscriber參數(shù)其實(shí)就是我們?cè)谡{(diào)用subscribe()進(jìn)行訂閱時(shí)時(shí)傳入的觀察者Observer。所以當(dāng)在call()方法中調(diào)用的5次onNext()方法與1次onCompleted()方法后峰搪,觀察者Observer中輸出的日志為:

onNext:xulei0
onNext:xulei1
onNext:xulei2
onNext:xulei3
onNext:xulei4
onCompleted

有的碼友看到這里會(huì)對(duì)call()方法中的subscriber參數(shù)就是訂閱時(shí)傳入的Observer有些不解岔冀,那么我們一起來看源碼。

先看下call()方法中的參數(shù)Subscriber:

public abstract class Subscriber<T> implements Observer<T>, Subscription {
    ......
}

可以看出Subscriber是Observer的抽象實(shí)現(xiàn)類概耻,與Observer一個(gè)類型使套。再來看訂閱時(shí)調(diào)用的subscribe(observer)方法:

public final Subscription subscribe(final Observer<? super T> observer) {
    //無視
    if (observer instanceof Subscriber) {
        return subscribe((Subscriber<? super T>)observer);
    }
    return subscribe(new Subscriber<T>() {
        
        @Override
        public void onCompleted() {
            observer.onCompleted();
        }
        
        @Override
        public void onError(Throwable e) {
            observer.onError(e);
        }
    
        @Override
        public void onNext(T t) {
            observer.onNext(t);
        }
    });
}

這里將傳入的Observer對(duì)象通過代理轉(zhuǎn)換為Subscriber對(duì)象作為參數(shù)傳入并調(diào)用重載方法subscribe(),我們?cè)賮砜催@個(gè)subscribe()方法的代碼:

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

這里繼續(xù)調(diào)用重載方法subscribe()鞠柄,將由Observer轉(zhuǎn)換為的subscriber對(duì)象與當(dāng)前Observable對(duì)象作為參數(shù)傳入侦高,繼續(xù)往下追蹤源碼:

private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
    ......
    subscriber.onStart();
    ......
    try {
        hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
        return hook.onSubscribeReturn(subscriber);
    } catch (Throwable e) {
        ......
        return Subscriptions.unsubscribed();
    }
}

精簡(jiǎn)一下代碼發(fā)現(xiàn),subscriber.onStart()用來通知被觀察者準(zhǔn)備開始發(fā)送事件了厌杜。重點(diǎn)看hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);我們發(fā)現(xiàn)hook.onSubscribeStart(observable, observable.onSubscribe)方法返回的是其第二個(gè)參數(shù)observable.onSubscribe矫膨,這個(gè)參數(shù)正是新建Observable時(shí)create()方法中傳入的OnSubscribe對(duì)象。接著又通過這個(gè)onSubscribe調(diào)用call(subscriber)方法,將subscriber作為參數(shù)傳入侧馅,碼友們有沒有發(fā)現(xiàn)危尿,這個(gè)subscriber傳來傳去究其根源,正是一開始由訂閱方法subscribe(observer)傳入的observer通過代理轉(zhuǎn)換為的那個(gè)subscriber馁痴。

這樣前后邏輯就連接上了谊娇,通過閱讀源碼我們才能發(fā)現(xiàn)為何創(chuàng)建Observable時(shí)call()方法中的subscriber參數(shù)其實(shí)就是訂閱時(shí)傳入的Observer。

總結(jié)

到此罗晕,本篇關(guān)于RxJava的基本原理與使用就講解完畢了济欢,下一篇我們將一起研究RxJava的四類操作符中的創(chuàng)建操作符都有哪些以及如何使用。

這里感謝下張磊大神撰寫的RxJava系列的幫助:
RxJava系列2(基本概念及使用介紹)

技術(shù)渣一枚小渊,有寫的不對(duì)的地方歡迎大神們留言指正法褥,有什么疑惑或者建議也可以在我Github上RxJavaDemo項(xiàng)目Issues中提出,我會(huì)及時(shí)回復(fù)酬屉。

附上RxJavaDemo的地址:
RxJavaDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末半等,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呐萨,更是在濱河造成了極大的恐慌杀饵,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谬擦,死亡現(xiàn)場(chǎng)離奇詭異切距,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)惨远,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門谜悟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人北秽,你說我怎么就攤上這事赌躺。” “怎么了羡儿?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)是钥。 經(jīng)常有香客問我掠归,道長(zhǎng),這世上最難降的妖魔是什么悄泥? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任虏冻,我火速辦了婚禮,結(jié)果婚禮上弹囚,老公的妹妹穿的比我還像新娘厨相。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布蛮穿。 她就那樣靜靜地躺著庶骄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪践磅。 梳的紋絲不亂的頭發(fā)上单刁,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音府适,去河邊找鬼羔飞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛檐春,可吹牛的內(nèi)容都是我干的逻淌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼疟暖,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼卡儒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起誓篱,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤朋贬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后窜骄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锦募,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年邻遏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了糠亩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡准验,死狀恐怖赎线,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情糊饱,我是刑警寧澤垂寥,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站另锋,受9級(jí)特大地震影響滞项,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜夭坪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一文判、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧室梅,春花似錦戏仓、人聲如沸疚宇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敷待。三九已至,卻和暖如春嗓奢,著一層夾襖步出監(jiān)牢的瞬間讼撒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工股耽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留根盒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓物蝙,卻偏偏與公主長(zhǎng)得像炎滞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诬乞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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