Rxjava2入門教程二:Observable與Observer響應(yīng)式編程在Rxjava2中的典型實現(xiàn)

如需下載源碼,請訪問
https://github.com/fengchuanfang/Rxjava2Tutorial
本篇文章對應(yīng)的Demo類為:com.edward.edward.Rxjava2Demo.Rxjava2_2_Observable
文章原創(chuàng),轉(zhuǎn)載請注明出處:
Rxjava2入門教程二:Observable與Observer響應(yīng)式編程在Rxjava2中的典型實現(xiàn)

運行源碼缭裆,打開app炬灭,點擊Demo圖標(biāo)潜必,可進(jìn)入以下頁面

RxjavaTutorial.png


在RxJava中每币,函數(shù)響應(yīng)式編程具體表現(xiàn)為一個觀察者(Observer)訂閱一個可觀察對象(Observable)先壕,通過創(chuàng)建可觀察對象發(fā)射數(shù)據(jù)流翔脱,經(jīng)過一系列操作符(Operators)加工處理和線程調(diào)度器(Scheduler)在不同線程間的轉(zhuǎn)發(fā)奴拦,最后由觀察者接受并做出響應(yīng)的一個過程
ObservableSource與Observer是RxJava2中最典型的一組觀察者與可觀察對象的組合,其他四組可以看做是這一組的改進(jìn)版或者簡化版届吁。

Observable

抽象類Observable是接口ObservableSource下的一個抽象實現(xiàn)错妖,我們可以通過Observable創(chuàng)建一個可觀察對象發(fā)射數(shù)據(jù)流。

     Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("Hello World");
                emitter.onComplete();
            }
        });

調(diào)用Observable.create方法疚沐,創(chuàng)建一個可觀察對象暂氯,并通過onNext發(fā)送一條數(shù)據(jù)“Hello World”,然后通過onComplete發(fā)送完成通知亮蛔。

Observer

創(chuàng)建一個觀察者Observer來接受并響應(yīng)可觀察對象發(fā)射的數(shù)據(jù)

Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(String s) {
                System.out.println(s);
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onComplete() {
                System.out.println("接受完成");
            }
        };

在onNext方法中接收到可觀察對象發(fā)射的數(shù)據(jù)"Hello World",并做出響應(yīng)——打印到控制臺痴施。

Observer訂閱Observable

observable.subscribe(observer);

通過subscribe方法,使Observer與Observable建立訂閱關(guān)系,Observer與Observable便成為了一個整體晾剖,Observer便可對Observable中的行為作出響應(yīng)锉矢。

Emitter/Observer

通過Observable.create創(chuàng)建可觀察對象時,我們可以發(fā)現(xiàn)具體執(zhí)行發(fā)射動作的是由接口ObservableEmitter的實例化對象完成的齿尽,而ObservableEmitter<T> 繼承自 接口Emitter<T>沽损,查看源碼接口Emitter的具體代碼如下:

public interface Emitter<T> {
        //用來發(fā)送數(shù)據(jù),可多次調(diào)用循头,每調(diào)用一次發(fā)送一條數(shù)據(jù)
    void onNext(@NonNull T value);
        //用來發(fā)送異常通知绵估,只發(fā)送一次,若多次調(diào)用只發(fā)送第一條
    void onError(@NonNull Throwable error);
        //用來發(fā)送完成通知卡骂,只發(fā)送一次国裳,若多次調(diào)用只發(fā)送第一條
    void onComplete();
}

onNext:用來發(fā)送數(shù)據(jù),可多次調(diào)用全跨,每調(diào)用一次發(fā)送一條數(shù)據(jù)
onError:用來發(fā)送異常通知缝左,只發(fā)送一次,若多次調(diào)用只發(fā)送第一條
onComplete:用來發(fā)送完成通知浓若,只發(fā)送一次渺杉,若多次調(diào)用只發(fā)送第一條

onError與onComplete互斥,兩個方法只能調(diào)用一個不能同時調(diào)用

數(shù)據(jù)在發(fā)送時挪钓,出現(xiàn)異呈窃剑可以調(diào)用onError發(fā)送異常通知也可以不調(diào)用,因為其所在的方法subscribe會拋出異常碌上,

若數(shù)據(jù)在全部發(fā)送完之后均正常倚评,可以調(diào)用onComplete發(fā)送一條完成通知

接口Observer中的三個方法(onNext,onError,onComplete)正好與Emitter中的三個方法相對應(yīng),對于Emitter中對應(yīng)方法發(fā)送的數(shù)據(jù)或通知進(jìn)行響應(yīng)馏予。

步驟簡化

去掉中間變量可以對之前的代碼簡化為以下形式:

    public void demo2() {
        Observable
                .create(new ObservableOnSubscribe<String>() {
                    @Override
                    public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                        emitter.onNext("Hello World");
                        emitter.onComplete();
                    }
                })
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(String s) {
                        System.out.println(s);
                    }

                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onComplete() {
                        System.out.println("接受完成");
                    }
                });
    }

再應(yīng)用Rxjava中強大的操作符天梧,可以將代碼簡化成以下形式:

    public void demo3() {
        Observable.just("Hello World")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                });
    }

再通過λ表達(dá)式,可進(jìn)一步簡化

    public void demo3_1() {
        Observable.just("Hello World").subscribe(System.out::println);
    }

其中霞丧,just操作符可用來發(fā)送單條數(shù)據(jù)呢岗,數(shù)字,字符串蚯妇,數(shù)組,對象暂筝,集合都可以當(dāng)做單條數(shù)據(jù)發(fā)送箩言。
Consumer可以看做是對觀察者Observer功能單一化之后的產(chǎn)物——消費者,上例中的Consumer通過其函數(shù)accept只接收可觀察對象發(fā)射的數(shù)據(jù)焕襟,不接收異常信息或完成信息陨收。
如果想接收異常信息或完成信息可以用下面的代碼:

    public void demo4() {
        Observable.just("Hello World")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        throwable.printStackTrace();
                    }
                }, new Action() {
                    @Override
                    public void run() throws Exception {
                        System.out.println("接受完成");
                    }
                });
    }

第二個參數(shù)Consumer規(guī)定泛型<Throwable>通過函數(shù)accept接收異常信息。
第三個參數(shù)Action也是對觀察者Observer功能單一化之后的產(chǎn)物--行動,通過函數(shù)run接收完成信息务漩,作出響應(yīng)行動拄衰。

發(fā)送數(shù)據(jù)序列

Observable可以發(fā)送單條數(shù)據(jù)也可以發(fā)送數(shù)據(jù)序列
通過最基礎(chǔ)的方法發(fā)送數(shù)據(jù)序列:

public void demo5(final List<String> list) {
        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                try {
                    for (String str : list) {
                        emitter.onNext(str);
                    }
                    emitter.onComplete();
                } catch (Exception e) {
                    emitter.onError(e);
                }
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(String s) {
                System.out.println(s);
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onComplete() {
                System.out.println("接受完成");
            }
        });
    }

在subscribe方法中,遍歷集合list中的String元素饵骨,通過emitter.onNext(str)逐一發(fā)送翘悉;發(fā)送完成后通過emitter.onComplete()發(fā)送完成通知;如果發(fā)送過程中遇到異常居触,通過emitter.onError(e)發(fā)送異常信息妖混。
Observer中通過onNext接收emitter發(fā)送的每一條信息并打印到控制臺(emitter發(fā)送幾次,Observer便接收幾次)轮洋,通過onError(Throwable e)接收異常信息制市,onComplete()接收完成信息。
同樣可以通過操作符對其進(jìn)行簡化弊予,如下;

    public void demo6(final List<String> list) {
        Observable
                .fromIterable(list)
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                });
    }

再用λ表達(dá)式祥楣,進(jìn)一步簡化

    public void demo6_1(final List<String> list) {
        Observable.fromIterable(list).subscribe(System.out::println);
    }

其中fromIterable操作符,可用來將一個可迭代對象中的元素逐一發(fā)送

Disposable

在之前的例子中汉柒,可以看到Observer接口中還有一個方法

public void onSubscribe(Disposable d) {
}

是在觀察者Observer與可觀察對象Observable误褪,建立訂閱關(guān)系后,回調(diào)這個方法竭翠,并且傳過來一個Disposable類型的參數(shù)振坚,可通過Disposable來控制Observer與Observable之間的訂閱。
無論觀察者Observer以何種方式訂閱可觀察對象Observable斋扰,都會生成一個Disposable渡八,如下:

public void demo7(final List<String> list) {
        Disposable disposable1 = Observable.just("Hello World")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                });
        Disposable disposable2 = Observable
                .fromIterable(list)
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                });
    }

查看Disposable接口的源碼,如下:

public interface Disposable {
        void dispose();
        boolean isDisposed();
}

其中isDisposed()方法用來判斷當(dāng)前訂閱是否失效传货,dispose()方法用來取消當(dāng)前訂閱屎鳍。
只有當(dāng)觀察者Observer與可觀察對象Observable之間建立訂閱關(guān)系,并且訂閱關(guān)系有效時问裕,Observer才能對Observable進(jìn)行響應(yīng)逮壁。如果Observer在響應(yīng)Observable的過程中,訂閱關(guān)系被取消粮宛,則Observer無法對取消訂閱關(guān)系之后Observable的行為作出響應(yīng)窥淆。
運行下面的代碼,當(dāng)Observable接收到第5條數(shù)據(jù)時巍杈,取消訂閱關(guān)系忧饭。

public void demo8() {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; i < 10; i++) {
                    System.out.println("發(fā)送" + i);
                    emitter.onNext(i);
                }
                emitter.onComplete();
            }
        }).subscribe(new Observer<Integer>() {
            private Disposable disposable;

            @Override
            public void onSubscribe(Disposable d) {
                disposable = d;
            }

            @Override
            public void onNext(Integer integer) {
                System.out.println("接收" + integer);
                if (integer > 4) disposable.dispose();
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onComplete() {
                System.out.println("數(shù)據(jù)接受完成");
            }
        });
    }

控制臺日志如下:

 I/System.out: 發(fā)送0
 I/System.out: 接收0
 I/System.out: 發(fā)送1
 I/System.out: 接收1
 I/System.out: 發(fā)送2
 I/System.out: 接收2
 I/System.out: 發(fā)送3
 I/System.out: 接收3
 I/System.out: 發(fā)送4
 I/System.out: 接收4
 I/System.out: 發(fā)送5
 I/System.out: 接收5
 I/System.out: 發(fā)送6
 I/System.out: 發(fā)送7
 I/System.out: 發(fā)送8
 I/System.out: 發(fā)送9

可以發(fā)現(xiàn)取消訂閱關(guān)系之前,Observable發(fā)送一條數(shù)據(jù)筷畦,Observe便接收一條词裤,但是取消訂閱關(guān)系之后刺洒,Observe將不再接收Observable發(fā)送的數(shù)據(jù)。

上一篇:Rxjava2入門教程一:函數(shù)響應(yīng)式編程及概述
下一篇吼砂;Rxjava2入門教程三:Operators操作符

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逆航,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子渔肩,更是在濱河造成了極大的恐慌因俐,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赖瞒,死亡現(xiàn)場離奇詭異女揭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)栏饮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門吧兔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袍嬉,你說我怎么就攤上這事境蔼。” “怎么了伺通?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵箍土,是天一觀的道長。 經(jīng)常有香客問我罐监,道長吴藻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任弓柱,我火速辦了婚禮沟堡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘矢空。我一直安慰自己航罗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布屁药。 她就那樣靜靜地躺著粥血,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酿箭。 梳的紋絲不亂的頭發(fā)上复亏,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音缭嫡,去河邊找鬼缔御。 笑死,一個胖子當(dāng)著我的面吹牛械巡,可吹牛的內(nèi)容都是我干的刹淌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼讥耗,長吁一口氣:“原來是場噩夢啊……” “哼有勾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起古程,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蔼卡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后挣磨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雇逞,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年茁裙,在試婚紗的時候發(fā)現(xiàn)自己被綠了塘砸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡晤锥,死狀恐怖掉蔬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矾瘾,我是刑警寧澤女轿,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站壕翩,受9級特大地震影響蛉迹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜放妈,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一北救、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧大猛,春花似錦扭倾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至唉堪,卻和暖如春模聋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唠亚。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工链方, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灶搜。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓祟蚀,卻偏偏與公主長得像工窍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子前酿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

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