RxJava操作符系列一

detail.jpg

前言

第一次接觸學(xué)習(xí)RxJava應(yīng)該是一兩個月前的事情了社裆,但其中也是斷斷續(xù)續(xù)翁授,最近又再次去學(xué)習(xí)RxJava残拐,和當(dāng)初剛接觸RxJava完全不是同樣的心情涎拉,輕松了很多瑞侮,也感受到了RxJava的魅力,真是不由衷感嘆太牛了鼓拧。目前關(guān)于RxJava的文章也很多半火,個人推薦兩篇扔物線的給 Android 開發(fā)者的 RxJava 詳解和大頭鬼Bruce的譯文 深入淺出RxJava系列。那么這篇文章通過代碼介紹RxJava中的操作符季俩,以及操作符的使用钮糖。當(dāng)然操作符較多,準(zhǔn)備分幾篇文章介紹酌住。如果你想提前學(xué)習(xí)其他操作符可以去GitHub,歡迎star項目店归。


RxJava操作符源碼傳送門


基礎(chǔ)介紹

為了力求有沒有RxJava基礎(chǔ)都能看懂此文,簡單介紹一下RxJava以及一些名詞酪我。在RxJava開源的Github上是這樣解釋的a library for composing asynchronous and event-based programs using observable sequences for the Java VM消痛。無論多么復(fù)雜的邏輯,都可以保持整潔的代碼格式都哭。

在RxJava中最重要的就是Observable(被觀察者)秩伞,subscribe(訂閱),Observer(觀察者)或者Subscriber(訂閱者)欺矫,Observable也就是數(shù)據(jù)(事件)源纱新,Subscriber負責(zé)接收以及處理數(shù)據(jù)(事件)。當(dāng)然要想實現(xiàn)兩者通信穆趴,需要有一種機制那就是訂閱脸爱。Observer 通過 subscribe() 方法實現(xiàn)訂閱關(guān)系,從而 Observable 可以在需要的時候發(fā)出事件來通知 Observer未妹。

例如張三(觀察者)想看某款新聞軟件的科技信息(被觀察者)阅羹,由于科技信息是每天推送或者不定時推送勺疼,如果張三一直盯著手機屏幕看并且刷新消息是不是又新的信息,顯然不現(xiàn)實捏鱼。這時候就可以通過張三 subscribe(訂閱)科技信息执庐,而實現(xiàn)當(dāng)有新的科技信息時自動給張三推送消息,在這期間导梆,張三并不需要一直盯著屏幕刷新聞轨淌。在我們平時的認知中實現(xiàn)訂閱應(yīng)該是張三.subscribe(科技新聞),不過在RxJava代碼中實現(xiàn)訂閱應(yīng)該寫成科技新聞.subscribe(張三)看尼。

在RxJava中递鹉,有三個事件回調(diào)方法,分別是onNext(),OnError(),onCompleted(),onNext()是最終輸出及處理數(shù)據(jù)的回調(diào)藏斩,在發(fā)射數(shù)據(jù)過程中出現(xiàn)錯誤異常會回調(diào)OnError()方法躏结,當(dāng)不會再有新的 onNext() 發(fā)出時,需要觸發(fā) onCompleted() 方法作為標(biāo)志狰域。,OnError()和onCompleted()是互斥的媳拴。下面舉一個最簡單的例子

        Observable observable2 = Observable.just("也許當(dāng)初忙著微笑和哭泣", "忙著追逐天空中的流星", "人理所當(dāng)然的忘記", "是誰風(fēng)里雨里一直默默守護在原地");
        Subscriber subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: " )
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: ")
            }

            @Override
            public void onNext(String s) {
               Log.e(TAG, "onNext: "+s )
            }
        };
        observable.subscribe(subscriber);

運行后打印信息為

onNext: 也許當(dāng)初忙著微笑和哭泣
onNext: 忙著追逐天空中的流星
onNext: 人理所當(dāng)然的忘記
onNext: 是誰風(fēng)里雨里一直默默守護在原地
onCompleted: 

Create

我們可以使用該操作符從零開始創(chuàng)建一個Observable,給這個操作符傳遞一個接受觀察者作為參數(shù)的函數(shù)兆览,并調(diào)用觀察者的onNext屈溉,onError和onCompleted方法。如下

        //被觀察者
        Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                //可以多次調(diào)用subscriber.onNext("大家好")發(fā)射數(shù)據(jù)
                subscriber.onNext("大家好");
                subscriber.onNext("我開始學(xué)習(xí)RxJava");
                subscriber.onCompleted();

            }
        });

發(fā)送數(shù)據(jù)需要在毀掉方法call中調(diào)用subscriber的onNext(),onNext(T)發(fā)送的參數(shù)需要和Observable.OnSubscribe<T>()中參數(shù)相同抬探,在上面我們傳入的是String類型子巾。創(chuàng)建后Observale后,我們需要創(chuàng)建Subscriber(觀察者)去處理observable發(fā)送的數(shù)據(jù)小压。如下

        Subscriber<String> subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted");
            }
            @Override
            public void onError(Throwable e) {
                Log.e(TAG, e.getMessage());
            }
            @Override
            public void onNext(String s) {
                Log.e(TAG, "onNext:"+s);
            }
        };

數(shù)據(jù)成功發(fā)送后线梗,會回調(diào)Subscriber的onNext()的方法,其中的參數(shù)就是接收到的數(shù)據(jù)怠益。當(dāng)onNext()接收數(shù)據(jù)完畢后會執(zhí)行onCompleted(),如果中途有環(huán)節(jié)出現(xiàn)錯誤異常仪搔,會執(zhí)行onError()。現(xiàn)在觀察者和被觀察者都創(chuàng)建完畢了溉痢,他們執(zhí)行還需要一個前提就是訂閱,如果不訂閱憋他,observable并不會發(fā)射數(shù)據(jù)孩饼,subscribe也不會接收數(shù)據(jù),訂閱代碼如下

observable.subscribe(subscriber);

執(zhí)行后輸出信息

onNext:大家好
onNext:我開始學(xué)習(xí)RxJava
onCompleted

from

該操作符是將其它種類的對象和數(shù)據(jù)類型轉(zhuǎn)換為Observable竹挡,如果當(dāng)你發(fā)射的的數(shù)據(jù)是同一種類型镀娶,而不是混合使用Observables和其它類型的數(shù)據(jù),會非常方便揪罕。如下創(chuàng)建Observable

        Integer[] integers = {1,2, 3, 4};
        Observable<Integer> observable=Observable.from(integers);
         Subscriber<String> subscriber = new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted");
            }
            @Override
            public void onError(Throwable e) {
                Log.e(TAG, e.getMessage());
            }
            @Override
            public void onNext(Integer i) {
                Log.e(TAG, "onNext:"+i);
            }
        };
        observable.subscribe(subscriber);
        

輸出信息為

onNext:1
onNext:2
onNext:3
onNext:4
onCompleted

from操作符可以轉(zhuǎn)換Future梯码、Iterable和數(shù)組宝泵。對于Iterable和數(shù)組,產(chǎn)生的Observable會發(fā)射Iterable或數(shù)組的每一項數(shù)據(jù)轩娶。對于Future,它會發(fā)射Future.get()方法返回的單個數(shù)據(jù)鳄抒,并且還可以增加通過: from(Future,timeout, timeUnit)指定超時時間许溅,如果執(zhí)行的時候Future超時會回調(diào)onError()方法。

just

just將單個數(shù)據(jù)轉(zhuǎn)換為發(fā)射那個數(shù)據(jù)的Observable茬祷,Just類似于From祭犯,但是From會將數(shù)組或Iterable的數(shù)據(jù)取出然后逐個發(fā)射借卧,而Just只是簡單的原樣發(fā)射铐刘,將數(shù)組或Iterable當(dāng)做單個數(shù)據(jù),如果你傳遞null給Just檩禾,它會返回一個發(fā)射null值的Observable盼产。不要誤認為它會返回一個空Observable(完全不發(fā)射任何數(shù)據(jù)的Observable)勺馆。對于just可以接收1到10個數(shù)據(jù),返回一個按參數(shù)列表順序發(fā)射這些數(shù)據(jù)的Observable灌灾。

        Observable.just(1 2, 3, 4)
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: ");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: ");
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.e(TAG, "onNext: " + integer);
                    }
                });

輸出

onNext:1
onNext:2
onNext:3
onNext:4
onCompleted:

對于just參數(shù)類型可以是多種锋喜,如下嘿般,傳入兩個類型數(shù)據(jù)

Observable.just(0, "one", 6, "two", 8, "three")
                .subscribe(new Subscriber<Serializable>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: " );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: ");
                    }

                    @Override
                    public void onNext(Serializable serializable) {
                        Log.e(TAG, "onNext: "+serializable.toString());
                    }
                });

則輸出信息

onNext:0
onNext:one
onNext:6
onNext:two
onNext:8
onNext:three
onCompleted:

Empty/Never/Error

Empty:創(chuàng)建一個不發(fā)射任何數(shù)據(jù)但是正常終止的Observable炉奴,此時會回調(diào)onCompleted()

Never:創(chuàng)建一個不發(fā)射數(shù)據(jù)也不終止的Observable

Error:創(chuàng)建一個不發(fā)射數(shù)據(jù)以一個錯誤終止的Observable

error操作符需要一個Throwable參數(shù)盆佣,你的Observable會以此終止共耍。這些操作符默認不在任何特定的調(diào)度器上執(zhí)行,但是empty和error有一個可選參數(shù)是Scheduler穆咐,如果你傳遞了Scheduler參數(shù)对湃,它們會在你指定的調(diào)度器上發(fā)送通知拍柒。

Range

該操作符創(chuàng)建特定整數(shù)序列的Observable屈暗,它接受兩個參數(shù),一個是范圍的起始值种呐,一個是范圍的數(shù)據(jù)的數(shù)目弃甥。如果你將第二個參數(shù)設(shè)為0淆攻,將導(dǎo)致Observable不發(fā)射任何數(shù)據(jù)(如果設(shè)置為負數(shù),會拋異常)啸箫。

        Observable.range(1,4)
                .subscribe(new Subscriber<Integer>() {
                    public String TAG="RXJAVA";

                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: " );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: ");
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.e(TAG, "onNext: "+integer);
                    }
                });

輸出信息

onNext: 1
onNext: 2
onNext: 3
onNext: 4
onCompleted: 

你可以在代碼實戰(zhàn)中筐高,更改第二個參數(shù)為負數(shù)柑土,或者0绊汹,以及將第一個參數(shù)更改為你想測試的任意值西乖,去觀察執(zhí)行日志幫助理解。

Timer

Timer操作符創(chuàng)建一個在給定的時間段之后返回一個特殊值的Observable薄腻。它在延遲一段給定的時間后發(fā)射一個簡單的數(shù)字0 庵楷。

Observable.timer(1, TimeUnit.SECONDS)
                .subscribe(new Subscriber<Long>() {
                    public String TAG="RXJAVA";

                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: " );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: ");
                    }

                    @Override
                    public void onNext(Long integer) {
                        Log.e(TAG, "onNext:1111111 "+integer);
                    }
                });

對于該操作符默認在computation調(diào)度器上執(zhí)行的尽纽,如果你想在onNext()回調(diào)方法更新UI,需要通過observeOn(AndroidSchedulers.mainThread())設(shè)置童漩,否則會調(diào)用onError()方法矫膨。當(dāng)然Time人提供的有一個三個參數(shù)的方法timer(long,TimeUnit,Scheduler)可以指定 Scheduler 豆拨。

Interval

該操作符按固定的時間間隔發(fā)射一個無限遞增的整數(shù)序列,它接受一個表示時間間隔的參數(shù)和一個表示時間單位的參數(shù)脚线,當(dāng)然該操作符合Timer一樣弥搞,是在computation調(diào)度器上執(zhí)行的攀例,若想更新UI需要指定Scheduler 為AndroidSchedulers.mainThread()挖胃。

     Subscription   subscription = Observable.interval(1, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        tv.append(" " + aLong + "   ");
                    }
                });

通過上面代碼就會每隔1秒在tv上追加一個數(shù)字,并且會永遠執(zhí)行烁登。如果在某個時刻不想繼續(xù)輸出,就需要要解除訂閱蔚舀。

        if (subscription != null && !subscription.isUnsubscribed()) {
            subscription.unsubscribe();
        }

Repeat

該操作符是重復(fù)的發(fā)射某個數(shù)據(jù)序列饵沧,并且可以自己設(shè)置重復(fù)的次數(shù)。當(dāng)接收到onComplete()會觸發(fā)重訂閱再次重復(fù)發(fā)射數(shù)據(jù),當(dāng)重復(fù)發(fā)射數(shù)據(jù)次數(shù)到達后執(zhí)行onCompleted()赌躺。

        String[] strs = {"也許當(dāng)初忙著微笑和哭泣", "忙著追逐天空中的流星"};
        Observable.from(strs).repeat(2)..subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: " );
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: ");
            }

            @Override
            public void onNext(String s) {
                Log.e(TAG, "onNext: "+s );
                tv1.append("\n" + s);
            }
        });

輸出

onNext: 也許當(dāng)初忙著微笑和哭泣
onNext: 忙著追逐天空中的流星
onNext: 也許當(dāng)初忙著微笑和哭泣
onNext: 忙著追逐天空中的流星
onCompleted: 

Defer

直到有觀察者訂閱時才創(chuàng)建Observable狼牺,并且為每個觀察者創(chuàng)建一個新的Observable,該操作符能保證訂閱執(zhí)行時數(shù)據(jù)源是最新的數(shù)據(jù)礼患。如下正常代碼

        String test="舊數(shù)據(jù)";
        Observable observable=Observable.just(test);
        Subscriber subscriber=new Subscriber() {
            public String TAG="RXJAVA";

            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: " );
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: " );
            }

            @Override
            public void onNext(Object o) {
                Log.e(TAG, "onNext: "+o );
            }
        };
        test="新數(shù)據(jù)";
        observable.subscribe(subscriber);

輸出

 onNext: 舊數(shù)據(jù)
 onCompleted: 

通過上面代碼和輸出日志發(fā)現(xiàn)锁右,雖然在后面講數(shù)據(jù)test更新為新數(shù)據(jù),但是并沒有生效讶泰,要想使用最新的數(shù)據(jù)就需要使用defer操作符咏瑟。此時更改使用defer

        test="舊數(shù)據(jù)";
        Observable<String> observable=Observable.defer(new Func0<Observable<String>>() {
            @Override
            public Observable<String> call() {
                return Observable.just(test);
            }
        });
        Subscriber subscriber=new Subscriber() {
            public String TAG="RXJAVA";

            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: " );
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: " );
            }

            @Override
            public void onNext(Object o) {
                Log.e(TAG, "onNext: "+o );
            }
        };
        test="新數(shù)據(jù)";
        observable.subscribe(subscriber);

輸出信息

onNext: 新數(shù)據(jù)
onCompleted: 

通過新的打印信息,發(fā)現(xiàn)輸出值已經(jīng)是最新的數(shù)據(jù)痪署。

到這里码泞,這篇文章暫時就先結(jié)束了,若文章有不足或者錯誤的地方狼犯,歡迎指正余寥,以防止給其他讀者錯誤引導(dǎo)。更多的操作符悯森,將在接下來的幾篇文章介紹宋舷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瓢姻,隨后出現(xiàn)的幾起案子祝蝠,更是在濱河造成了極大的恐慌,老刑警劉巖幻碱,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绎狭,死亡現(xiàn)場離奇詭異,居然都是意外死亡褥傍,警方通過查閱死者的電腦和手機儡嘶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恍风,“玉大人蹦狂,你說我怎么就攤上這事誓篱。” “怎么了凯楔?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵燕鸽,是天一觀的道長。 經(jīng)常有香客問我啼辣,道長,這世上最難降的妖魔是什么御滩? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任鸥拧,我火速辦了婚禮,結(jié)果婚禮上削解,老公的妹妹穿的比我還像新娘续崖。我一直安慰自己映屋,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喳资,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岂膳。 梳的紋絲不亂的頭發(fā)上绪穆,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音蓖扑,去河邊找鬼唉铜。 笑死,一個胖子當(dāng)著我的面吹牛律杠,可吹牛的內(nèi)容都是我干的潭流。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼柜去,長吁一口氣:“原來是場噩夢啊……” “哼灰嫉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嗓奢,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤讼撒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后股耽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體椿肩,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年豺谈,在試婚紗的時候發(fā)現(xiàn)自己被綠了郑象。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡茬末,死狀恐怖厂榛,靈堂內(nèi)的尸體忽然破棺而出盖矫,到底是詐尸還是另有隱情,我是刑警寧澤击奶,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布辈双,位于F島的核電站,受9級特大地震影響柜砾,放射性物質(zhì)發(fā)生泄漏湃望。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一痰驱、第九天 我趴在偏房一處隱蔽的房頂上張望证芭。 院中可真熱鬧,春花似錦担映、人聲如沸废士。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽官硝。三九已至,卻和暖如春短蜕,著一層夾襖步出監(jiān)牢的瞬間氢架,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工朋魔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留达箍,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓铺厨,卻偏偏與公主長得像缎玫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子解滓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

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

  • 本篇文章介主要紹RxJava中操作符是以函數(shù)作為基本單位赃磨,與響應(yīng)式編程作為結(jié)合使用的,對什么是操作洼裤、操作符都有哪些...
    嘎啦果安卓獸閱讀 2,851評論 0 10
  • 注:只包含標(biāo)準(zhǔn)包中的操作符邻辉,用于個人學(xué)習(xí)及備忘參考博客:http://blog.csdn.net/maplejaw...
    小白要超神閱讀 2,186評論 2 8
  • 作者: maplejaw本篇只解析標(biāo)準(zhǔn)包中的操作符。對于擴展包腮鞍,由于使用率較低值骇,如有需求,請讀者自行查閱文檔移国。 創(chuàng)...
    maplejaw_閱讀 45,632評論 8 93
  • 創(chuàng)建操作 用于創(chuàng)建Observable的操作符Create通過調(diào)用觀察者的方法從頭創(chuàng)建一個ObservableEm...
    rkua閱讀 1,814評論 0 1
  • 注:本系列文章主要用于博主個人學(xué)習(xí)記錄吱瘩,本文末尾附上了一些較好的文章提供學(xué)習(xí)。轉(zhuǎn)載請附 原文鏈接RxJava學(xué)習(xí)系...
    黑丫山上小旋風(fēng)閱讀 2,133評論 1 5