本篇文章介主要紹RxJava中操作符是以函數(shù)作為基本單位,與響應(yīng)式編程作為結(jié)合使用的,對(duì)什么是操作、操作符都有哪些以及RxJava中的操作符進(jìn)行介紹,最后介紹一下RxJava操作符在android app開(kāi)發(fā)實(shí)際生產(chǎn)中使用情況。
目錄
一.編程方式介紹
1.函數(shù)式編程
2.響應(yīng)式編程
3.函數(shù)響應(yīng)式編程
二、操作符介紹
1.什么是操作符?
2.RxJava中的操作符簡(jiǎn)介
3.RxJava中的操作符分類(lèi)
三、操作符在Android中的應(yīng)用實(shí)踐
1.線程切換注意事項(xiàng)
2.線程的生命周期
3.線程池的使用
一、編程方式介紹
常見(jiàn)的編程方式有函數(shù)式編程、響應(yīng)式編程、命令式編程、面向?qū)ο缶幊獭⒚嫦蚪涌诰幊獭⒚嫦蜻^(guò)程編程。RxJava函數(shù)響應(yīng)式編程是將函數(shù)式編程與響應(yīng)式編程的結(jié)合。
-
1.函數(shù)式編程
函數(shù)是什么?根據(jù)入?yún)⒌玫椒祷刂怠ava中的方法、C中的函數(shù)、JavaScript中的function。在編程語(yǔ)言中方法的參數(shù)可以是方法(函數(shù)),返回值也可以是方法(函數(shù)),適用于計(jì)算處理的場(chǎng)景。函數(shù)式編程是編程中是一種手段或者方法。被重新提出和重視。
函數(shù)式編程有一些特點(diǎn):
純函數(shù)的定義是,對(duì)于相同的輸入,永遠(yuǎn)會(huì)得到相同的輸出,而且沒(méi)有任何可觀察的副作用,也不依賴(lài)外部環(huán)境的狀態(tài)。int method1(int a, int b);
函數(shù)柯里化(curry)的定義很簡(jiǎn)單:傳遞給函數(shù)一部分參數(shù)來(lái)調(diào)用它,讓它返回一個(gè)函數(shù)去處理剩下的參數(shù)。
var add = function(x){
return function(y){
return x + y
}
}
var add = x => (y => x + y); // js ES6寫(xiě)法,也是比較正統(tǒng)的函數(shù)式寫(xiě)法
函數(shù)組:學(xué)會(huì)了使用純函數(shù)以及如何把它柯里化之后,我們會(huì)很容易寫(xiě)出這樣的“包菜式”代碼:h(g(f(x)));
高階函數(shù):就是參數(shù)為函數(shù)或者返回值為函數(shù)的函數(shù),有了高階函數(shù),就可以將復(fù)用力度降低到函數(shù)級(jí)別,相對(duì)于面向?qū)ο笳Z(yǔ)言,復(fù)用的力度更低
閉包:函數(shù)編程支持函數(shù)作為第一類(lèi)對(duì)象,有時(shí)稱(chēng)為閉包或者仿函數(shù)(functor)對(duì)象。實(shí)質(zhì)上,閉包是起函數(shù)的作用并可以像對(duì)象一樣操作的對(duì)象。
惰性求值:函數(shù)式編程語(yǔ)言還提供惰性求值(Lazy evaluation,也稱(chēng)作call-by-need),是在將表達(dá)式賦值給變量(或稱(chēng)作綁定)時(shí)并不計(jì)算表達(dá)式的值,而在變量第一次被使用時(shí)才進(jìn)行計(jì)算。這樣就可以通過(guò)避免不必要的求值提升性能。
無(wú)狀態(tài) 變量的不變性,入?yún)⑹菬o(wú)變化的。
簡(jiǎn)單說(shuō),"函數(shù)式編程"是一種"編程范式"(programming paradigm),也就是如何編寫(xiě)程序的方法論。它屬于"結(jié)構(gòu)化編程"的一種,主要思想是把運(yùn)算過(guò)程盡量寫(xiě)成一系列嵌套的函數(shù)調(diào)用。函數(shù)式編程是給軟件開(kāi)發(fā)者提供的另一套工具箱,為我們提供了另外一種抽象和思考的方式。Lambda演算在最初設(shè)計(jì)的時(shí)候就是為了研究計(jì)算相關(guān)的問(wèn)題。所以函數(shù)式編程主要解決的也是計(jì)算問(wèn)題,函數(shù)式編程是一種編程模型,他將計(jì)算機(jī)運(yùn)算看做是數(shù)學(xué)中函數(shù)的計(jì)算,并且避免了狀態(tài)以及變量的概念。函數(shù)式編程的抽象本質(zhì)則是將函數(shù)也作為一個(gè)抽象單位,而反映成代碼形式,則是高階函數(shù)。
-
2.響應(yīng)式編程
響應(yīng)式編程就是與異步數(shù)據(jù)流交互的編程范式。在某種程度上,這并不是什么新東西。事件總線(Event buses)或咱們常見(jiàn)的單擊事件就是一個(gè)異步事件流,你可以觀察這個(gè)流,也可以基于這個(gè)流做一些自定義操作(原文:side effects,副作用,本文皆翻譯為自定義操作)。響應(yīng)式就是基于這種想法。你能夠創(chuàng)建所有事物的數(shù)據(jù)流,而不僅僅只是單擊和懸停事件數(shù)據(jù)流。 流廉價(jià)且無(wú)處不在,任何事物都可以當(dāng)作一個(gè)流:變量、用戶(hù)輸入、屬性、緩存、數(shù)據(jù)結(jié)構(gòu)等等。比如,假設(shè)你的微博評(píng)論就是一個(gè)跟單擊事件一樣的數(shù)據(jù)流,你能夠監(jiān)聽(tīng)這個(gè)流,并做出響應(yīng)。響應(yīng)式編程(Reactive Programming 或稱(chēng)反應(yīng)式編程)是一種流行的編程方法,編寫(xiě)代碼是基于對(duì)變化的反應(yīng)。它的靈感來(lái)自于我們的日常生活,也即我們?nèi)绾尾扇⌒袆?dòng)以及與他人溝通。和平常經(jīng)常聽(tīng)說(shuō)的面向?qū)ο缶幊毯秃瘮?shù)式編程一樣,響應(yīng)式編程(Reactive Programming)就是一個(gè)編程范式,但是與其他編程范式不同的是它是基于數(shù)據(jù)流和變化傳播的。
我們經(jīng)常在程序中這樣寫(xiě) A = B + C
A被賦值為B和C的值。這時(shí),如果我們改變B的值,A的值并不會(huì)隨之改變。而如果我們運(yùn)用一種機(jī)制,當(dāng)B或者C的值發(fā)現(xiàn)變化的時(shí)候,A的值也隨之改變,這樣就實(shí)現(xiàn)了”響應(yīng)式“。而響應(yīng)式編程的提出,其目的就是簡(jiǎn)化類(lèi)似的操作,因此它在用戶(hù)界面編程領(lǐng)域以及基于實(shí)時(shí)系統(tǒng)的動(dòng)畫(huà)方面都有廣泛的應(yīng)用。另一方面,在處理嵌套回調(diào)的異步事件,復(fù)雜的列表過(guò)濾和變換的時(shí)候也都有良好的表現(xiàn)。Reactive響應(yīng)式(反應(yīng)式)編程 是一種新的編程風(fēng)格,其特點(diǎn)是異步或并發(fā)、事件驅(qū)動(dòng)、推送PUSH機(jī)制以及觀察者模式的衍生。reactive應(yīng)用(響應(yīng)式應(yīng)用)允許開(kāi)發(fā)人員構(gòu)建事件驅(qū)動(dòng)(event-driven),可擴(kuò)展性,彈性的反應(yīng)系統(tǒng):提供高度敏感的實(shí)時(shí)的用戶(hù)體驗(yàn)感覺(jué),可伸縮性和彈性的應(yīng)用程序棧的支持,隨時(shí)可以部署在多核和云計(jì)算架構(gòu)。
響應(yīng)式編程特點(diǎn)
- 響應(yīng)性是指一個(gè)系統(tǒng)應(yīng)該總是能夠及時(shí)響應(yīng)用戶(hù)請(qǐng)求,并且保持很低的延遲。
- 彈性是指一個(gè)系統(tǒng)即使在部分組件開(kāi)始出現(xiàn)故障的情況下也應(yīng)該能夠作出響應(yīng),將停機(jī)時(shí)間將至最低。
- 可伸縮性是指一個(gè)系統(tǒng)在負(fù)載增加時(shí)應(yīng)該能夠根據(jù)需求增加資源以確保響應(yīng)性,但同時(shí)也應(yīng)該能在負(fù)載降低時(shí)減少資源,保持高效的資源利用率。
- 消息驅(qū)動(dòng)是指在一個(gè)系統(tǒng)的不同部分之間傳遞消息
響應(yīng)式流是一種規(guī)范,下面三個(gè)重要的概念是響應(yīng)式流API的構(gòu)建基礎(chǔ):
- 發(fā)布者是事件的發(fā)送方,可以向它訂閱。
- 訂閱者是事件訂閱方。
- 訂閱將發(fā)布者和訂閱者聯(lián)系起來(lái),使訂閱者可以向發(fā)布者發(fā)送信號(hào)。
響應(yīng)式編程是一種基于異步數(shù)據(jù)流概念的編程模式。數(shù)據(jù)流就像一條河:它可以被觀測(cè),被過(guò)濾,被操作,或者為新的消費(fèi)者與另外一條流合并為一條新的流。響應(yīng)式編程的一個(gè)關(guān)鍵概念是事件。事件可以被等待,可以觸發(fā)過(guò)程,也可以觸發(fā)其它事件。事件是唯一的以合適的方式將我們的現(xiàn)實(shí)世界映射到我們的軟件中:如果屋里太熱了我們就打開(kāi)一扇窗戶(hù)。同樣的,當(dāng)我們更改電子表(變化的傳播)中的一些數(shù)值時(shí),我們需要更新整個(gè)表格或者我們的機(jī)器人碰到墻時(shí)會(huì)轉(zhuǎn)彎(響應(yīng)事件)。
-
3.函數(shù)響應(yīng)式編程
FRP與普通的函數(shù)式編程相似,但是每個(gè)函數(shù)可以接收一個(gè)輸入值的流,如果其中,一個(gè)新的輸入值到達(dá)的話(huà),這個(gè)函數(shù)將根據(jù)最新的輸入值重新計(jì)算,并且產(chǎn)生一個(gè)新的輸出。這是一種”數(shù)據(jù)流"編程模式。
而主要利用函數(shù)式編程(Functional Programming)的思想和方法(函數(shù)、高階函數(shù))來(lái)支持Reactive Programming就是所謂的Functional Reactive Programming,簡(jiǎn)稱(chēng)FRP。FPR 將輸入分為兩個(gè)基礎(chǔ)的部分:行為(behavior)和事件(events) 。這兩個(gè)基本元素在函數(shù)響應(yīng)式編程中都是第一類(lèi)(first-class)值。 其中行為是隨時(shí)間連續(xù)變化的數(shù)據(jù),而事件則是基于離散的時(shí)間序列 。例如:在我們操作網(wǎng)頁(yè)的時(shí)候,會(huì)觸發(fā)很多的事件,包括點(diǎn)擊,拖動(dòng),按鍵事件等。這些事件都是不連續(xù)的。對(duì)事件求值是沒(méi)有意義的,所有我們一般要通過(guò)fromEvent,buffer等將其變成連續(xù)的行為來(lái)做進(jìn)一步處理。與RP相比,F(xiàn)RP更偏重于底層。由于采用了函數(shù)式編程范式,F(xiàn)RP也自然而然帶有其特點(diǎn)。這其中包括了不可變性,沒(méi)有副作用以及通過(guò)組合函數(shù)來(lái)構(gòu)建程序等特點(diǎn)。
二、操作符介紹
- 1.什么是操作符?
指令系統(tǒng)的每一條指令都有一個(gè)操作符,它表示該指令應(yīng)進(jìn)行什么性質(zhì)的操作。
操作符,常見(jiàn)于計(jì)算機(jī)語(yǔ)言之中,不同的指令用操作符這個(gè)字段的不同編碼來(lái)表示,每一種編碼代表一種指令。
指令系統(tǒng)的每一條指令都有一個(gè)操作符,它表示該指令應(yīng)進(jìn)行什么性質(zhì)的操作。不同的指令用操作符這個(gè)字段的不同編碼來(lái)表示,每一種編碼代表一種指令。組成操作符字段的位數(shù)一般取決于計(jì)算機(jī)指令系統(tǒng)的規(guī)模。
操作符用于操作數(shù)據(jù)并生成一個(gè)新值。
先看看大家熟悉的java操作符的相關(guān)的就比較好理解了。
Java的算數(shù)操作符與其它大多數(shù)程序設(shè)計(jì)語(yǔ)言都是相同的,其中包括加號(hào)(+)、減號(hào)(-)、乘號(hào)(×)、除號(hào)(÷)以及取模(%)。
也就是說(shuō) int i = j+k; 這個(gè)語(yǔ)句中的 “+” 就是一個(gè)操作符。“=”也是一個(gè)操作符,“+”為算數(shù)操作符、“=”為賦值操作符。
布爾操作符 !、 &&、 ||
關(guān)系比較操作符 < 、 <= 、 > 、>=、 != 、 == 、 === 、 !==
還有些人會(huì)發(fā)現(xiàn)這些都是編程語(yǔ)言級(jí)別的東西,怎么RxJava一個(gè)框架要定義這些東西?RxJava是 函數(shù)響應(yīng)式編程,是以函數(shù)作為基本元素,相較于原來(lái)的編程都是變量、常量、對(duì)象這些作為基本元素。
響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的編程范式。這意味著可以在編程語(yǔ)言中很方便地表達(dá)靜態(tài)或動(dòng)態(tài)的數(shù)據(jù)流,而相關(guān)的計(jì)算模型會(huì)自動(dòng)將變化的值通過(guò)數(shù)據(jù)流進(jìn)行傳播。
- 2.RxJava中的操作符簡(jiǎn)介
- 就是建立在變量、常量、對(duì)象這些編程方法的基礎(chǔ)上,搭建的另一種編程方式或者是編程語(yǔ)言,只是這個(gè)語(yǔ)言的基礎(chǔ)是原來(lái)的編程的方式。
通過(guò)RxJava中的規(guī)則完成編程的工作,這些規(guī)則的實(shí)現(xiàn)就是RxJava操作符。- RxJava將函數(shù)創(chuàng)建成RxJava中的元素Observable,然后進(jìn)行變換、條件篩選、過(guò)濾、組合等操作然后將處理的結(jié)果發(fā)送給接收者Observer。
- 這里邊的兩個(gè)英文單詞要區(qū)分清楚Observable 和Observer,一個(gè)是可被觀察者、一個(gè)是觀察者。可被觀察者Observable完成一系列操作后將數(shù)據(jù)發(fā)送給觀察者Observer,一個(gè)是發(fā)射者,一個(gè)是接收者。弄清楚了,下面的操作符就理解主體結(jié)構(gòu)了。
- 3.RxJava中的操作符分類(lèi)
像Java中有算數(shù)操作符加減乘除、邏輯操作符與或非、條件操作符大于小于等于這些。數(shù)據(jù)庫(kù)sql中過(guò)濾、篩選、count這樣的操作符。
RxJava也有它自己需要的操作符,分為了下面幾類(lèi):
- 1.直接創(chuàng)建一個(gè)Observable(創(chuàng)建操作)
- 2.組合多個(gè)Observable(組合操作)
- 3.對(duì)Observable發(fā)射的數(shù)據(jù)執(zhí)行變換操作(變換操作)
- 4.從Observable發(fā)射的數(shù)據(jù)中取特定的值(過(guò)濾操作)
- 5.這些操作符用于從錯(cuò)誤通知中恢復(fù)(錯(cuò)誤處理)
- 6.用于處理Observable的操作符(輔助操作)
- 7.轉(zhuǎn)發(fā)Observable的部分值(條件/布爾/過(guò)濾操作)
- 8.對(duì)Observable發(fā)射的數(shù)據(jù)序列求值(算術(shù)/聚合操作)
學(xué)習(xí)這些操作符按照編程語(yǔ)言的思想去學(xué)習(xí),這些操作符就比較好理解了。再看上幾個(gè)實(shí)例,這些操作符基本使用就會(huì)了,其他的知道有這些操作符,具體使用的時(shí)候再研究就可以搞定了。學(xué)習(xí)幾個(gè)實(shí)例就會(huì)明白這些操作符都是干什么的了。下面會(huì)主要以操作符的實(shí)現(xiàn)思想和實(shí)例的形式來(lái)介紹RxJava中的操作符。
(1)RxJava入門(mén)用法:
基礎(chǔ)知識(shí): RxJava最核心的兩個(gè)東西是Observables(被觀察者,事件源)和 Subscribers(觀察者)。 Observables發(fā)出一系列事件,Subscribers處理這些事件。 這里的事件可以是任何你感興趣的東西(觸摸事件,web接口調(diào)用返回的數(shù)據(jù)。。。)
// 觀察者, 創(chuàng)建事件
Observable<String> myObservable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> sub) {
sub.onNext("Hello, world!");
sub.onNext("Hello, world!");
sub.onNext("Hello, world!");
sub.onCompleted();
// sub.onError(new Exception("Observable throw onError exception!")); //onCompleted()和onError()不能同時(shí)使用
}
});
// 訂閱者 接收處理事件
Subscriber<String> mySubscriber = new Subscriber<String>() {
@Override
public void onNext(String s) {
System.out.println("onNext:" + s);
}
@Override
public void onCompleted() {
System.out.println("onCompleted!");
}
@Override
public void onError(Throwable e) {
System.out.println("onError:" + e.getMessage());
}
};
myObservable.subscribe(mySubscriber);
(2)RxJava入門(mén)用法的簡(jiǎn)化用法:
// 首先來(lái)看看如何簡(jiǎn)化Observable對(duì)象的創(chuàng)建過(guò)程。
// RxJava內(nèi)置了很多簡(jiǎn)化創(chuàng)建Observable對(duì)象的函數(shù),比如Observable.just就是用來(lái)創(chuàng)建只發(fā)出一個(gè)事件就結(jié)束的Observable對(duì)象,
// 上面創(chuàng)建Observable對(duì)象的代碼可以簡(jiǎn)化為一行
Observable<String> myObservable = Observable.just("Hello, world!");
// 接下來(lái)看看如何簡(jiǎn)化Subscriber,
// 上面的例子中,我們其實(shí)并不關(guān)心OnComplete和OnError,
// 我們只需要在onNext的時(shí)候做一些處理,這時(shí)候就可以使用Action1類(lèi)。
Action1<String> onNextAction = new Action1<String>() {
@Override
public void call(String s) {
System.out.println("call:" + s);
}
};
myObservable.subscribe(onNextAction);
// subscribe方法有一個(gè)重載版本,接受三個(gè)Action1類(lèi)型的參數(shù),分別對(duì)應(yīng)OnNext,OnComplete, OnError函數(shù)。
// myObservable.subscribe(onNextAction, onErrorAction, onCompleteAction);
(3)RxJava入門(mén)用法使用java8的lambda表達(dá)式
Observable.just("Hello, world!").subscribe(s -> System.out.println(s));//一行就搞定了
創(chuàng)建操作符 — 用于創(chuàng)建Observable的操作符,共有下面幾種,其中create、from、just是比較常用的操作符,在這里介紹下這三個(gè)操作符。
Create — 通過(guò)調(diào)用觀察者的方法從頭創(chuàng)建一個(gè)Observable
From — 將其它的對(duì)象或數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為Observable
Just — 將對(duì)象或者對(duì)象集合轉(zhuǎn)換為一個(gè)會(huì)發(fā)射這些對(duì)象的Observable
Defer — 在觀察者訂閱之前不創(chuàng)建這個(gè)Observable,為每一個(gè)觀察者創(chuàng)建一個(gè)新的Observable
Interval — 創(chuàng)建一個(gè)定時(shí)發(fā)射整數(shù)序列的Observable
Range — 創(chuàng)建發(fā)射指定范圍的整數(shù)序列的Observable
Repeat — 創(chuàng)建重復(fù)發(fā)射特定的數(shù)據(jù)或數(shù)據(jù)序列的Observable
Empty/Never/Throw — 創(chuàng)建行為受限的特殊Observable
Start — 創(chuàng)建發(fā)射一個(gè)函數(shù)的返回值的Observable
Timer — 創(chuàng)建在一個(gè)指定的延遲之后發(fā)射單個(gè)數(shù)據(jù)的Observable
(4)Create 操作符
通過(guò)調(diào)用觀察者的方法從頭創(chuàng)建一個(gè)Observable,是最基礎(chǔ)的創(chuàng)建操作符.
// 觀察者, 創(chuàng)建事件
Observable<String> myObservable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> sub) {
//Edit data
sub.onNext("Hello, world!");
sub.onCompleted();
}
});
// 訂閱者 接收處理事件
Subscriber<String> mySubscriber = new Subscriber<String>() {
@Override
public void onNext(String s) {
System.out.println("onNext:" + s);
onError(new Throwable("1"));
onError(new Throwable("2"));
}
@Override
public void onCompleted() {
System.out.println("onCompleted!");
}
@Override
public void onError(Throwable e) {
System.out.println("onError:" + e.getMessage());
}
};
myObservable.subscribe(mySubscriber);
(5)from操作符
它接收一個(gè)集合作為輸入,然后每次輸出一個(gè)元素給subscriber。
String[] urls = { "url1", "url2", "url3" };
Observable.from(urls).subscribe(url -> System.out.println(url));
(6)Just 操作符
將對(duì)象或者對(duì)象集合轉(zhuǎn)換為一個(gè)會(huì)發(fā)射這些對(duì)象的Observable,與from的區(qū)別:支持多個(gè)類(lèi)型作為入?yún)ⅲ项?lèi)型不是每次輸出一個(gè)元素,而是整個(gè)集合輸出。
String[] urls = { "url1", "url2", "url3" };
Observable.just("字符串", 123, true, urls).subscribe(item -> System.out.println(item));//這里的urls是一次發(fā)射出去的,不是拆分成數(shù)組后發(fā)射出去。
Observable.just("url1", "url2", "url3").subscribe(item -> System.out.println(item));
變換操作符 - 這些操作符可用于對(duì)Observable發(fā)射的數(shù)據(jù)進(jìn)行變換。map、Buffer、FlatMap是比較典型的變換操作符,在這里介紹下這三個(gè)操作符。
Map — 映射,通過(guò)對(duì)序列的每一項(xiàng)都應(yīng)用一個(gè)函數(shù)變換Observable發(fā)射的數(shù)據(jù),實(shí)質(zhì)是對(duì)序列中的每一項(xiàng)執(zhí)行一個(gè)函數(shù),函數(shù)的參數(shù)就是這個(gè)數(shù)據(jù)項(xiàng)
Buffer — 緩存,可以簡(jiǎn)單的理解為緩存,它定期從Observable收集數(shù)據(jù)到一個(gè)集合,然后把這些數(shù)據(jù)集合打包發(fā)射,而不是一次發(fā)射一個(gè)。
FlatMap — 扁平映射,將Observable發(fā)射的數(shù)據(jù)變換為Observables集合,然后將這些Observable發(fā)射的數(shù)據(jù)平坦化的放進(jìn)一個(gè)單獨(dú)的Observable,可以認(rèn)為是一個(gè)將嵌套的數(shù)據(jù)結(jié)構(gòu)展開(kāi)的過(guò)程。
ConcatMap — cancatMap操作符與flatMap操作符類(lèi)似,都是把Observable產(chǎn)生的結(jié)果轉(zhuǎn)換成多個(gè)Observable,然后把這多個(gè)。Observable“扁平化”成一個(gè)Observable,并依次提交產(chǎn)生的結(jié)果給訂閱者。與flatMap操作符不同的是,concatMap操作符在處理產(chǎn)生的。Observable時(shí),采用的是“連接(concat)”的方式,而不是“合并(merge)”的方式,這就能保證產(chǎn)生結(jié)果的順序性,也就是說(shuō)提交給訂閱者的結(jié)果是按照順序提交的,不會(huì)存在交叉的情況。
GroupBy — 分組,將原來(lái)的Observable分拆為Observable集合,將原始Observable發(fā)射的數(shù)據(jù)按Key分組,每一個(gè)Observable發(fā)射一組不同的數(shù)據(jù)。
Scan — 掃描,對(duì)Observable發(fā)射的每一項(xiàng)數(shù)據(jù)應(yīng)用一個(gè)函數(shù),然后按順序依次發(fā)射這些值。
Window — 窗口,定期將來(lái)自O(shè)bservable的數(shù)據(jù)分拆成一些Observable窗口,然后發(fā)射這些窗口,而不是每次發(fā)射一項(xiàng)。類(lèi)似于Buffer,但Buffer發(fā)射的是數(shù)據(jù),Window發(fā)射的是Observable,每一個(gè)Observable發(fā)射原始Observable的數(shù)據(jù)的一個(gè)子集。
(7)Map — 映射
通過(guò)對(duì)序列的每一項(xiàng)都應(yīng)用一個(gè)函數(shù)變換Observable發(fā)射的數(shù)據(jù),實(shí)質(zhì)是對(duì)序列中的每一項(xiàng)執(zhí)行一個(gè)函數(shù),函數(shù)的參數(shù)就是這個(gè)數(shù)據(jù)項(xiàng)。
關(guān)鍵詞:將Observable發(fā)射出的數(shù)據(jù)轉(zhuǎn)換成另外一個(gè)Observable。
Observable.just("http://www.baidu.com/", "http://www.google.com/", "https://www.bing.com/")
.map(new Func1<String, String>() {
@Override
public String call(String s) {
try {
URL url = new URL(s);
String host = url.getHost();
return InetAddress.getByName(host).toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println("subscribe : " + s);
}
});
(8)Buffer — 緩存
可以簡(jiǎn)單的理解為緩存,它定期從Observable收集數(shù)據(jù)到一個(gè)集合,然后把這些數(shù)據(jù)集合打包發(fā)射,而不是一次發(fā)射一個(gè)。
關(guān)鍵詞:將Observable攢著一塊發(fā)出去。
final String[] mails = new String[]{"Here is an email!", "Another email!", "Yet another email!"}; //定義郵件內(nèi)容
//每隔0.8秒就隨機(jī)發(fā)布一封郵件
Observable<String> endlessMail = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
try {
if (subscriber.isUnsubscribed()) return;
Random random = new Random();
while (true) {
String mail = mails[random.nextInt(mails.length)];
subscriber.onNext(mail);
Thread.sleep(800);
}
} catch (Exception ex) {
subscriber.onError(ex);
}
}
});
//把上面產(chǎn)生的郵件內(nèi)容緩存到列表中,并每隔2秒通知訂閱者
endlessMail.buffer(2, TimeUnit.SECONDS)
.subscribe(new Action1<List<String>>() {
@Override
public void call(List<String> list) {
System.out.println(String.format("You've got %d new messages! Here they are!", list.size()));
for (int i = 0; i < list.size(); i++)
System.out.println("**" + list.get(i).toString());
}
});
(9)FlatMap — 扁平映射
將Observable發(fā)射的數(shù)據(jù)變換為Observables集合,然后將這些Observable發(fā)射的數(shù)據(jù)的放進(jìn)一個(gè)單獨(dú)的Observable,可以認(rèn)為是一個(gè)將嵌套的數(shù)據(jù)結(jié)構(gòu)展開(kāi)的過(guò)程。
關(guān)鍵詞:將Observable發(fā)射出的數(shù)據(jù)轉(zhuǎn)換成多個(gè)Observable。提供了一個(gè)Observable轉(zhuǎn)換成多個(gè)Observable的能力。
- 在學(xué)習(xí)RxJava操作符的時(shí)候,Map和FlatMap比較難以理解。這里對(duì)FlatMap和Map的比較并做了針對(duì)性的介紹。
- 這里有兩個(gè)基礎(chǔ)點(diǎn)可以仔細(xì)琢磨一下:1.Observable對(duì)象既可以是一個(gè)元素也可以是一個(gè)集合。2.Map操作符是提供一對(duì)一的轉(zhuǎn)換、FlatMap是提供一對(duì)多的轉(zhuǎn)換。
- 下面是總結(jié)了Map和FlatMap的比較,可以參照分析出Map和FlatMap的操作符區(qū)別和作用。攻克了這兩個(gè)操作符也就可以說(shuō)基本明白R(shí)xJava操作符是怎么回事了。
- 【基礎(chǔ)知識(shí)】:Observable 對(duì)象 本身可以是一個(gè)對(duì)象也可以是一組對(duì)象
一個(gè)對(duì)象如:Observable.just(1) 結(jié)果是經(jīng)過(guò)發(fā)射器之后只發(fā)射一條數(shù)據(jù)
一組對(duì)象如:Observable.just(1,2,3) 或者 Observable.from({"222", "sss", "eee"})。結(jié)果是經(jīng)過(guò)發(fā)射器之后可以發(fā)射多條數(shù)據(jù)。- 【map和FlatMap的區(qū)別】:
- map 和FlatMap都能把參數(shù)轉(zhuǎn)化為另一個(gè)對(duì)象
map 是一對(duì)一的轉(zhuǎn)化 返回值是普通類(lèi)型 , 如String、File 返回值是單個(gè)轉(zhuǎn)換后的事件- FlatMap 一對(duì)多的轉(zhuǎn)化 返回值是Observable,如Observable<File>、Observable<String> 返回值是Observable(轉(zhuǎn)換后的Observable集合)
flatMap的返回類(lèi)型是Observable,說(shuō)明是可以返回多個(gè)內(nèi)容,而不是事件類(lèi)型String、List、或者數(shù)組(這些最終都是一個(gè)事件)。
FlatMap() 的原理是這樣的
- 使用傳入的事件對(duì)象創(chuàng)建一個(gè) Observable 對(duì)象;
- 并不發(fā)送這個(gè) Observable, 而是將它激活,于是它開(kāi)始發(fā)送事件; 【備注:這里的激活概念可以理解為這個(gè)操作Observable obs = Observable.from(file.listFiles());】
- 每一個(gè)創(chuàng)建出來(lái)的 Observable 發(fā)送的事件,都被匯入同一個(gè) Observable ,而這個(gè) Observable 負(fù)責(zé)將這些事件統(tǒng)一交給 Subscriber 的回調(diào)方法。
這三個(gè)步驟,把事件拆成了兩級(jí),通過(guò)一組新創(chuàng)建的 Observable 將初始的對(duì)象『鋪平』之后通過(guò)統(tǒng)一路徑分發(fā)了下去。而這個(gè)『鋪平』就是 flatMap() 所謂的 flat。
- 使用場(chǎng)景: FlatMap() 解決嵌套的問(wèn)題 一個(gè)入?yún)ⅲ祷囟鄠€(gè)事件,再根據(jù)多個(gè)事件,返回多個(gè)事件,這種嵌套問(wèn)題。 (一個(gè)返回多個(gè)的使用from就可以搞定)
Observable.just(new File("E:\\aa\\"))
.flatMap(new Func1<File, Observable<File>>() {
@Override
public Observable<File> call(File file) {//1. 使用傳入的事件對(duì)象創(chuàng)建一個(gè) Observable 對(duì)象; --------> file就是傳入的事件對(duì)象
return Observable.from(file.listFiles()); //2.中的并不發(fā)送這個(gè) Observable是個(gè)集合 ---> 就是這個(gè) Observable.from(file.listFiles())
}//3.每一個(gè)創(chuàng)建出來(lái)的 Observable --->這個(gè)Observable就是 就是(2)中激活出來(lái)的file.listFiles()中的每一個(gè)File的Observable對(duì)象
//3.都被匯入同一Observable 這個(gè)Observable 是 這個(gè)call方法的返回值 Observable<File>,這個(gè)Observable是個(gè)集合,也是返回的集合(也就是扁平化的為一個(gè)集合)
})
.flatMap(new Func1<File, Observable<File>>() {
@Override
public Observable<File> call(File file) {
return Observable.from(file.listFiles());
}
})
.subscribe(new Action1<File>() {
@Override
public void call(File file) {
System.out.println(file.getName());
}
});
FlatMap再來(lái)一個(gè)例子有助于理解
/**
* 【flatMap案例】
* 首先假設(shè)這么一種需求:假設(shè)有一個(gè)數(shù)據(jù)結(jié)構(gòu)『學(xué)生』,現(xiàn)在需要打印出一組學(xué)生的名字。實(shí)現(xiàn)方式很簡(jiǎn)單:用map轉(zhuǎn)換一下就可以了,此實(shí)現(xiàn)忽略
* 那么再假設(shè):如果要打印出每個(gè)學(xué)生所需要修的所有課程的名稱(chēng)呢?(需求的區(qū)別在于,每個(gè)學(xué)生只有一個(gè)名字,但卻有多個(gè)課程。)首先可以這樣實(shí)現(xiàn):將學(xué)生作為事件傳入for循環(huán)打印課程名稱(chēng)
* 如果不想使用for循環(huán)該怎么辦? -------------------flatMap 代碼見(jiàn)下方
* 用rx的方式再使用for循環(huán),就會(huì)覺(jué)得這個(gè)flatMap這個(gè)沒(méi)有什么意義了。就變的難理解,用以前能實(shí)現(xiàn)的東西,再學(xué)這個(gè)flatMap的抵觸。變成思維的轉(zhuǎn)變。。。
*/
public static void flatMap2(){
String[] courses1 = {"語(yǔ)文", "數(shù)學(xué)" , "英語(yǔ)", "數(shù)學(xué)1" , "英語(yǔ)1", "數(shù)學(xué)2" , "英語(yǔ)3", "數(shù)學(xué)5" , "英語(yǔ)6"};
String[] courses2 = {"語(yǔ)文111", "數(shù)學(xué)111" , "英語(yǔ)111", "數(shù)學(xué)1131" , "英語(yǔ)1141", "數(shù)學(xué)1511" , "英語(yǔ)1161"};
Student[] students = {new Student("xiaoli", courses1), new Student("zhangsan", courses2)};
Observable.from(students)
.flatMap(new Func1<Student, Observable<String>>() {
@Override
public Observable<String> call(Student student) {
return Observable.from(student.courses);
}
}).subscribe(new Action1<String>() {
@Override
public void call(String str) {
System.out.println(str);
}
});
}
static class Student{
public Student(String name, String[] courses){
this.name = name;
this.courses = courses;
}
public String name;
public String[] courses;
}
過(guò)濾操作符 - 這些操作符用于從Observable發(fā)射的數(shù)據(jù)中進(jìn)行選擇。這里介紹比較典型的filter、distinct、elementAt三個(gè)操作符。
- Debounce — 只有在空閑了一段時(shí)間后才發(fā)射數(shù)據(jù),通俗的說(shuō),就是如果一段時(shí)間沒(méi)有操作,就執(zhí)行一次操作
- Distinct — 去重,過(guò)濾掉重復(fù)數(shù)據(jù)項(xiàng)
- ElementAt — 取值,取特定位置的數(shù)據(jù)項(xiàng)
- Filter — 過(guò)濾,過(guò)濾掉沒(méi)有通過(guò)謂詞測(cè)試的數(shù)據(jù)項(xiàng),只發(fā)射通過(guò)測(cè)試的
- First — 首項(xiàng),只發(fā)射滿(mǎn)足條件的第一條數(shù)據(jù)
- IgnoreElements — 忽略所有的數(shù)據(jù),只保留終止通知(onError或onCompleted)
- Last — 末項(xiàng),只發(fā)射最后一條數(shù)據(jù)
- Sample — 取樣,定期發(fā)射最新的數(shù)據(jù),等于是數(shù)據(jù)抽樣,有的實(shí)現(xiàn)里叫ThrottleFirst
- Skip — 跳過(guò)前面的若干項(xiàng)數(shù)據(jù)
- SkipLast — 跳過(guò)后面的若干項(xiàng)數(shù)據(jù)
- Take — 只保留前面的若干項(xiàng)數(shù)據(jù)
- TakeLast — 只保留后面的若干項(xiàng)數(shù)據(jù)
(10)filter操作符
是對(duì)源Observable產(chǎn)生的結(jié)果按照指定條件進(jìn)行過(guò)濾,只有滿(mǎn)足條件的結(jié)果才會(huì)提交給訂閱者。
Observable.just(1, 2, 3, 4, 5)
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer item) {
return (item < 4);
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
(11)distinct操作符
對(duì)源Observable產(chǎn)生的結(jié)果進(jìn)行過(guò)濾,把重復(fù)的結(jié)果過(guò)濾掉,只輸出不重復(fù)的結(jié)果給訂閱者,非常類(lèi)似于SQL里的distinct關(guān)鍵字。
Observable.just(1, 2, 1, 1, 2, 3)
.distinct().subscribe(new Subscriber<Integer>() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.err.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
(12)elementAt操作符
在源Observable產(chǎn)生的結(jié)果中,僅僅把指定索引的結(jié)果提交給訂閱者,索引是從0開(kāi)始的。
Observable.just(1, 2, 3, 4, 5, 6)
.elementAt(5).subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
System.out.println("Next:" + integer);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
System.out.println("Error:" + throwable.getMessage());
}
}, new Action0() {
@Override
public void call() {
System.out.println("completed!");
}
});
組合操作符 -- 用于將多個(gè)Observable組合成一個(gè)單一的Observable,這里只是介紹個(gè)CombineLatest操作符,以對(duì)組合操作符了解即可。
- And/Then/When — 通過(guò)模式(And條件)和計(jì)劃(Then次序)組合兩個(gè)或多個(gè)Observable發(fā)射的數(shù)據(jù)集
- CombineLatest — 當(dāng)兩個(gè)Observables中的任何一個(gè)發(fā)射了一個(gè)數(shù)據(jù)時(shí),通過(guò)一個(gè)指定的函數(shù)組合每個(gè)Observable發(fā)射的最新數(shù)據(jù)(一共兩個(gè)數(shù)據(jù)),然后發(fā)射這個(gè)函數(shù)的結(jié)果
- Join — 無(wú)論何時(shí),如果一個(gè)Observable發(fā)射了一個(gè)數(shù)據(jù)項(xiàng),只要在另一個(gè)Observable發(fā)射的數(shù)據(jù)項(xiàng)定義的時(shí)間窗口內(nèi),就將兩個(gè)Observable發(fā)射的數(shù)據(jù)合并發(fā)射
- Merge — 將兩個(gè)Observable發(fā)射的數(shù)據(jù)組合并成一個(gè)
- StartWith — 在發(fā)射原來(lái)的Observable的數(shù)據(jù)序列之前,先發(fā)射一個(gè)指定的數(shù)據(jù)序列或數(shù)據(jù)項(xiàng)
- Switch — 將一個(gè)發(fā)射Observable序列的Observable轉(zhuǎn)換為這樣一個(gè)Observable:它逐個(gè)發(fā)射那些Observable最近發(fā)射的數(shù)據(jù)
- Zip — 打包,使用一個(gè)指定的函數(shù)將多個(gè)Observable發(fā)射的數(shù)據(jù)組合在一起,然后將這個(gè)函數(shù)的結(jié)果作為單項(xiàng)數(shù)據(jù)發(fā)射
(13)combineLatest操作符
把兩個(gè)Observable產(chǎn)生的結(jié)果進(jìn)行合并,合并的結(jié)果組成一個(gè)新的Observable。這兩個(gè)Observable中任意一個(gè)Observable產(chǎn)生的結(jié)果,都和另一個(gè)Observable最后產(chǎn)生的結(jié)果,按照一定的規(guī)則進(jìn)行合并。
關(guān)鍵詞:發(fā)射兩個(gè)Observable的合并結(jié)果
Integer[] array2 = { 10, 20, 30, 40, 50 };
Observable.combineLatest(Observable.just(4, 2,5), Observable.from(array2),
new Func2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer a, Integer b) {
//System.out.println("a:" + a + ",b:");
return a + b;
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
@Override
public void onError(Throwable e) {
System.err.println("Error: " + e.getMessage());
}
@Override
public void onNext(Integer a) {
System.out.println("Next: " + a);
}
});
異常處理操作符 -- 這些操作符用于從錯(cuò)誤通知中恢復(fù)。這里主要介紹下retry、onErrorReturn、onErrorResumeNext三個(gè)操作符。
- Catch — 捕獲,繼續(xù)序列操作,將錯(cuò)誤替換為正常的數(shù)據(jù),從onError通知中恢復(fù)
- Retry — 重試,如果Observable發(fā)射了一個(gè)錯(cuò)誤通知,重新訂閱它,期待它正常終止
- onErrorReturn - 方法 返回一個(gè)鏡像原有Observable行為的新Observable。會(huì)忽略前者的onError調(diào)用,不會(huì)將錯(cuò)誤傳遞給觀察者,而是發(fā)射一個(gè)特殊的項(xiàng)并調(diào)用觀察者的onCompleted方法。
- onErrorResumeNext - onErrorResumeNext方法與onErrorReturn()方法類(lèi)似,都是攔截原Observable的onError通知,不同的是攔截后的處理方式,onErrorReturn創(chuàng)建并返回一個(gè)特殊項(xiàng),而onErrorResumeNext創(chuàng)建并返回一個(gè)新的Observabl,觀察者會(huì)訂閱它,并接收其發(fā)射的數(shù)據(jù)。
- onExceptionResumeNext - onExceptionResumeNext方法與onErrorResumeNext方法類(lèi)似創(chuàng)建并返回一個(gè)擁有類(lèi)似原Observable的新Observable,,也使用這個(gè)備用的Observable。不同的是,如果onError收到的Throwable不是一個(gè)Exception,它會(huì)將錯(cuò)誤傳遞給觀察者的onError方法,不會(huì)使用備用的Observable。
- retryWhen - retryWhen和retry類(lèi)似,區(qū)別是,retryWhen將onError中的Throwable傳遞給一個(gè)函數(shù),這個(gè)函數(shù)產(chǎn)生另一個(gè)Observable,retryWhen觀察它的結(jié)果再?zèng)Q定是不是要重新訂閱原始的Observable。如果這個(gè)Observable發(fā)射了一項(xiàng)數(shù)據(jù),它就重新訂閱,如果這個(gè)Observable發(fā)射的是onError通知,它就將這個(gè)通知傳遞給觀察者然后終止。
(14)retry操作符
是當(dāng)Observable發(fā)生錯(cuò)誤或者異常時(shí),重新嘗試執(zhí)行Observable的邏輯,如果經(jīng)過(guò)n次重新嘗試執(zhí)行后仍然出現(xiàn)錯(cuò)誤或者異常,則最后回調(diào)執(zhí)行onError方法;當(dāng)然如果源Observable沒(méi)有錯(cuò)誤或者異常出現(xiàn),則按照正常流程執(zhí)行。
關(guān)鍵詞:observable.retry(1)
Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
if (subscriber.isUnsubscribed()) return;
//循環(huán)輸出數(shù)字
try {
for (int i = 0; i < 10; i++) {
if (i == 4) {
throw new Exception("this is number 4 error!");
}
subscriber.onNext(i);
}
subscriber.onCompleted();
} catch (Throwable e) {
subscriber.onError(e);
}
}
});
observable.retry(1).subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
@Override
public void onError(Throwable e) {
System.err.println("Error: " + e.getMessage());
}
@Override
public void onNext(Integer value) {
System.out.println("Next:" + value);
}
});
(15)onErrorReturn操作符
是在Observable發(fā)生錯(cuò)誤或異常的時(shí)候(即將回調(diào)oError方法時(shí)),攔截錯(cuò)誤并執(zhí)行指定的邏輯,返回一個(gè)跟源Observable相同類(lèi)型的結(jié)果,最后回調(diào)訂閱者的onComplete方法
關(guān)鍵詞:攔截error,并轉(zhuǎn)換處理
Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
if (subscriber.isUnsubscribed())
return;
// 循環(huán)輸出數(shù)字
try {
for (int i = 0; i < 10; i++) {
if (i == 4) {
throw new Exception("this is number 4 error!");
}
subscriber.onNext(i);
}
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
}
}
});
observable.onErrorReturn(new Func1<Throwable, Integer>() {
@Override
public Integer call(Throwable throwable) {
return 1004;
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
@Override
public void onError(Throwable e) {
System.err.println("Error: " + e.getMessage());
}
@Override
public void onNext(Integer value) {
System.out.println("Next:" + value);
}
});
(16)onErrorResumeNext操作符
跟onErrorReturn類(lèi)似,只不過(guò)onErrorReturn只能在錯(cuò)誤或異常發(fā)生時(shí)只返回一個(gè)和源Observable相同類(lèi)型的結(jié)果,而onErrorResumeNext操作符是在錯(cuò)誤或異常發(fā)生時(shí)返回一個(gè)Observable,也就是說(shuō)可以返回多個(gè)和源Observable相同類(lèi)型的結(jié)果。
關(guān)鍵詞:與onErrorReturn相比可以返回多個(gè)結(jié)果。
Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
if (subscriber.isUnsubscribed())
return;
// 循環(huán)輸出數(shù)字
try {
for (int i = 0; i < 10; i++) {
if (i == 4) {
throw new Exception("this is number 4 error!");
}
subscriber.onNext(i);
}
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
}
}
});
observable.onErrorResumeNext(new Func1<Throwable, Observable<? extends Integer>>() {
@Override
public Observable<? extends Integer> call(Throwable throwable) {
return Observable.just(100, 101, 102, 103);
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
@Override
public void onError(Throwable e) {
System.err.println("Error: " + e.getMessage());
}
@Override
public void onNext(Integer value) {
System.out.println("Next:" + value);
}
});
算術(shù)、聚合、連接操作符 -- 這里主要介紹count、reduce、public三個(gè)操作符。
算術(shù)聚合操作符
- Average — 計(jì)算Observable發(fā)射的數(shù)據(jù)序列的平均值,然后發(fā)射這個(gè)結(jié)果
- Concat — 不交錯(cuò)的連接多個(gè)Observable的數(shù)據(jù)
- Count — 計(jì)算Observable發(fā)射的數(shù)據(jù)個(gè)數(shù),然后發(fā)射這個(gè)結(jié)果
- Max — 計(jì)算并發(fā)射數(shù)據(jù)序列的最大值
- Min — 計(jì)算并發(fā)射數(shù)據(jù)序列的最小值
- Reduce — 按順序?qū)?shù)據(jù)序列的每一個(gè)應(yīng)用某個(gè)函數(shù),然后返回這個(gè)值
- Sum — 計(jì)算并發(fā)射數(shù)據(jù)序列的和
- 連接操作符
- Connect — 指示一個(gè)可連接的Observable開(kāi)始發(fā)射數(shù)據(jù)給訂閱者
- Publish — 將一個(gè)普通的Observable轉(zhuǎn)換為可連接的
- RefCount — 使一個(gè)可連接的Observable表現(xiàn)得像一個(gè)普通的Observable
- Replay — 確保所有的觀察者收到同樣的數(shù)據(jù)序列,即使他們?cè)贠bservable開(kāi)始發(fā)射數(shù)據(jù)之后才訂閱
(17)Count操作符
將一個(gè)Observable轉(zhuǎn)換成一個(gè)發(fā)射單個(gè)值的Observable,這個(gè)值表示原始Observable發(fā)射的數(shù)據(jù)的數(shù)量。如果原始Observable發(fā)生錯(cuò)誤終止,Count不發(fā)射數(shù)據(jù)而是直接傳遞錯(cuò)誤通知。如果原始Observable永遠(yuǎn)不終止,Count既不會(huì)發(fā)射數(shù)據(jù)也不會(huì)終止。
關(guān)鍵詞:只發(fā)射數(shù)量,不關(guān)心內(nèi)容。
Subscriber<Integer> mySubscriber = new Subscriber<Integer>() {
@Override
public void onNext(Integer s) {
System.out.println("onNext:" + s);
}
@Override
public void onCompleted() {
System.out.println("onCompleted!");
}
@Override
public void onError(Throwable e) {
System.out.println("onError:" + e.getMessage());
}
};
Observable.from(new String[] { "one", "two", "three" })
.count()
.subscribe(mySubscriber);
(18)Reduce操作符
對(duì)原始Observable發(fā)射數(shù)據(jù)的第一項(xiàng)應(yīng)用一個(gè)函數(shù),然后再將這個(gè)函數(shù)的返回值與第二項(xiàng)數(shù)據(jù)一起傳遞給函數(shù),以此類(lèi)推,持續(xù)這個(gè)過(guò)程直到原始Observable發(fā)射它的最后一項(xiàng)數(shù)據(jù)并終止,此時(shí)Reduce返回的Observable發(fā)射這個(gè)函數(shù)返回的最終值。 注意如果原始Observable沒(méi)有發(fā)射任何數(shù)據(jù),reduce拋出異常IllegalArgumentException。 在其它場(chǎng)景中,這種操作有時(shí)被稱(chēng)為累積,聚集,壓縮,折疊,注射等。
關(guān)鍵字:疊加,返回疊加結(jié)果
Observable.just(1,2,3,4)
.reduce(new Func2<Integer, Integer, Integer>() {
//integer為前面幾項(xiàng)只和,integer2為當(dāng)前發(fā)射的數(shù)據(jù)
@Override
public Integer call(Integer integer, Integer integer2) {
//System.out.println("integer:"+integer+" integer2:"+integer2);
return integer+integer2;
}
}).subscribe(integer -> System.out.println("reduce:"+integer));
(19)Publish 操作符
將普通的Observable轉(zhuǎn)換為可連接的Observable(ConnectableObservable),ConnectableObservable是Observable的子類(lèi)。 可連接的Observable (connectable Observable)與普通的Observable差不多,不過(guò)它并不會(huì)在被訂閱時(shí)開(kāi)始發(fā)射數(shù)據(jù),而是直到使用了Connect操作符時(shí)才會(huì)開(kāi)始,這樣可以更靈活的控制發(fā)射數(shù)據(jù)的時(shí)機(jī)。 注意:如果一個(gè)ConnectableObservable已經(jīng)開(kāi)始發(fā)射數(shù)據(jù),再對(duì)其進(jìn)行訂閱只能接受之后發(fā)射的數(shù)據(jù),訂閱之前已經(jīng)發(fā)射過(guò)的數(shù)據(jù)就丟失了。
關(guān)鍵詞:發(fā)射可以控制,訂閱完不會(huì)立即發(fā)射。
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Observable<Long> obs = Observable.interval(1, TimeUnit.SECONDS).take(5);
//使用publish操作符將普通Observable轉(zhuǎn)換為可連接的Observable
ConnectableObservable<Long> connectableObservable = obs.publish();
//第一個(gè)訂閱者訂閱,不會(huì)開(kāi)始發(fā)射數(shù)據(jù)
connectableObservable.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
System.out.println("1.onCompleted");
}
@Override
public void onError(Throwable e) {
System.out.println("1.onError");
}
@Override
public void onNext(Long along) {
System.out.println("1.onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
//開(kāi)始發(fā)射數(shù)據(jù)
System.out.println("start time:" + sdf.format(new Date()));
connectableObservable.connect();
//第二個(gè)訂閱者延遲2s訂閱,這將導(dǎo)致丟失前面2s內(nèi)發(fā)射的數(shù)據(jù)
connectableObservable.delaySubscription(2, TimeUnit.SECONDS)
.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
System.out.println("2.onCompleted");
}
@Override
public void onError(Throwable e) {
System.out.println("2.onError");
}
@Override
public void onNext(Long along) {
System.out.println("2.onNext:"+along+"->time:"+ sdf.format(new Date()));
}
});
條件和布爾操作 -- 這些操作符可用于單個(gè)或多個(gè)數(shù)據(jù)項(xiàng),也可用于Observable。這里主要介紹all、amb、skipUtil這三個(gè)操作符。
- All — 判斷Observable發(fā)射的所有的數(shù)據(jù)項(xiàng)是否都滿(mǎn)足某個(gè)條件
- Amb — 給定多個(gè)Observable,只讓第一個(gè)發(fā)射數(shù)據(jù)的Observable發(fā)射全部數(shù)據(jù)
- Contains — 判斷Observable是否會(huì)發(fā)射一個(gè)指定的數(shù)據(jù)項(xiàng)
- DefaultIfEmpty — 發(fā)射來(lái)自原始Observable的數(shù)據(jù),如果原始Observable沒(méi)有發(fā)射數(shù)據(jù),就發(fā)射一個(gè)默認(rèn)數(shù)據(jù)
- SequenceEqual — 判斷兩個(gè)Observable是否按相同的數(shù)據(jù)序列
- SkipUntil — 丟棄原始Observable發(fā)射的數(shù)據(jù),直到第二個(gè)Observable發(fā)射了一個(gè)數(shù)據(jù),然后發(fā)射原始Observable的剩余數(shù)據(jù)
- SkipWhile — 丟棄原始Observable發(fā)射的數(shù)據(jù),直到一個(gè)特定的條件為假,然后發(fā)射原始Observable剩余的數(shù)據(jù)
- TakeUntil — 發(fā)射來(lái)自原始Observable的數(shù)據(jù),直到第二個(gè)Observable發(fā)射了一個(gè)數(shù)據(jù)或一個(gè)通知
- TakeWhile — 發(fā)射原始Observable的數(shù)據(jù),直到一個(gè)特定的條件為真,然后跳過(guò)剩余的數(shù)據(jù)
(20)All操作符
對(duì)Observable發(fā)送的所有數(shù)據(jù)根據(jù)某個(gè)條件進(jìn)行判斷,當(dāng)其發(fā)射出去的數(shù)據(jù)都滿(mǎn)足該條件時(shí),則返回true,否則返回false。
關(guān)鍵點(diǎn):都滿(mǎn)足該條件,才發(fā)送一個(gè)true,否則返回false。
Observable.just(2, 2, 1, 4).all(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
//System.out.println("integer:" + integer);
if (integer % 2 == 0) {
return true;
} else {
return false;
}
}
}).subscribe(flag -> System.out.println(flag));
(21)Amb操作符
是對(duì)2到9個(gè)Observable進(jìn)行處理,這些Observable會(huì)形成一種競(jìng)爭(zhēng)關(guān)系,當(dāng)哪個(gè)Observable最先發(fā)射出數(shù)據(jù),則amb進(jìn)行發(fā)射這個(gè)Observable里的數(shù)據(jù),而其它的Observable將被丟棄。
關(guān)鍵字:只發(fā)送其中一組,其他組被拋棄
Subscriber<Integer> mySubscriber = new Subscriber<Integer>() {
@Override
public void onNext(Integer s) {
System.out.println("onNext:" + s);
}
@Override
public void onCompleted() {
System.out.println("onCompleted!");
}
@Override
public void onError(Throwable e) {
System.out.println("onError:" + e.getMessage());
}
};
Observable.amb(
createDelayObservable(4),
createDelayObservable(3),
createDelayObservable(2),
createDelayObservable(1))//發(fā)射出去的是這個(gè),內(nèi)容是1,2,3
.subscribe(mySubscriber);
(22)SkipUtil操作符
是根據(jù)一個(gè)目標(biāo)Observable為基準(zhǔn),當(dāng)目標(biāo)Observable沒(méi)發(fā)射出去數(shù)據(jù)的時(shí),原Observable發(fā)射出去的數(shù)據(jù)將會(huì)被忽略,當(dāng)目標(biāo)Observable發(fā)射數(shù)據(jù)時(shí),則原Observable才開(kāi)始發(fā)射數(shù)據(jù)。
關(guān)鍵詞:skipUntil(Observable.just(100))這個(gè)是目標(biāo),他發(fā)射數(shù)據(jù)之前,原來(lái)的Observable發(fā)射出去的數(shù)據(jù)將會(huì)被忽略
Subscriber<Long> mySubscriber = new Subscriber<Long>() {
@Override
public void onNext(Long s) {
System.out.println("onNext:" + s);
}
@Override
public void onCompleted() {
System.out.println("onCompleted!");
}
@Override
public void onError(Throwable e) {
System.out.println("onError:" + e.getMessage());
}
};
Observable.interval(1, TimeUnit.SECONDS) .skipUntil(Observable.just(100).delay(5, TimeUnit.SECONDS))//延遲5s發(fā)送,目標(biāo)Observable
//.skipUntil(Observable.timer(5, TimeUnit.SECONDS))
.subscribe(mySubscriber);
輔助操作符 -- 輔助操作一組用于處理Observable的操作符.這里介紹下delay、do、SubscribeOn三個(gè)操作符。
- Delay — 延遲一段時(shí)間發(fā)射結(jié)果數(shù)據(jù)
- Do — 注冊(cè)一個(gè)動(dòng)作占用一些Observable的生命周期事件,相當(dāng)于Mock某個(gè)操作
- Materialize/Dematerialize — 將發(fā)射的數(shù)據(jù)和通知都當(dāng)做數(shù)據(jù)發(fā)射,或者反過(guò)來(lái)
- ObserveOn — 指定觀察者觀察Observable的調(diào)度程序(工作線程)
- Serialize — 強(qiáng)制Observable按次序發(fā)射數(shù)據(jù)并且功能是有效的
- Subscribe — 收到Observable發(fā)射的數(shù)據(jù)和通知后執(zhí)行的操作
- SubscribeOn — 指定Observable應(yīng)該在哪個(gè)調(diào)度程序上執(zhí)行
- TimeInterval — 將一個(gè)Observable轉(zhuǎn)換為發(fā)射兩個(gè)數(shù)據(jù)之間所耗費(fèi)時(shí)間的Observable
- Timeout — 添加超時(shí)機(jī)制,如果過(guò)了指定的一段時(shí)間沒(méi)有發(fā)射數(shù)據(jù),就發(fā)射一個(gè)錯(cuò)誤通知
- Timestamp — 給Observable發(fā)射的每個(gè)數(shù)據(jù)項(xiàng)添加一個(gè)時(shí)間戳
- Using — 創(chuàng)建一個(gè)只在Observable的生命周期內(nèi)存在的一次性資源
(23)delay
讓原始Observable在發(fā)射每項(xiàng)數(shù)據(jù)之前都暫停一段指定的時(shí)間段,結(jié)果是Observable發(fā)射的數(shù)據(jù)項(xiàng)在時(shí)間上整體延后一段時(shí)間.注意:delay不會(huì)平移onError通知,它會(huì)立即將這個(gè)通知傳遞給訂閱者,同時(shí)丟棄任何待發(fā)射的onNext通知。但是它會(huì)平移一個(gè)onCompleted通知。
Observable<Integer> obs = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
for (int i = 0; i < 5; i++) {
if (i > 2) {
// subscriber.onError(new Throwable("VALUE TO MAX"));
// //delay不會(huì)平移onError通知
}
subscriber.onNext(i);
}
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.computation());
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
/*
* Delay操作符讓原始Observable在發(fā)射每項(xiàng)數(shù)據(jù)之前都暫停一段指定的時(shí)間段。
* 效果是Observable發(fā)射的數(shù)據(jù)項(xiàng)在時(shí)間上向前整體平移了一個(gè)增量
*
* 注意:delay不會(huì)平移onError通知,它會(huì)立即將這個(gè)通知傳遞給訂閱者,同時(shí)丟棄任何待發(fā)射的onNext通知。
* 然而它會(huì)平移一個(gè)onCompleted通知。
*/
System.out.println("delay start:" + sdf.format(new Date()));
obs.delay(2, TimeUnit.SECONDS).subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
System.out.println("delay onCompleted" + sdf.format(new Date()));
}
@Override
public void onError(Throwable e) {
System.out.println("delay onError" + e.getMessage());
}
@Override
public void onNext(Integer integer) {
System.out.println("delay onNext:" + sdf.format(new Date()) + "->" + integer);
}
});
(24)Do系列操作符就是為原始Observable的生命周期事件注冊(cè)一個(gè)回調(diào),當(dāng)Observable的某個(gè)事件發(fā)生時(shí)就會(huì)調(diào)用這些回調(diào)。
- RxJava實(shí)現(xiàn)了很多doxxx操作符
- doOnEach:為 Observable注冊(cè)這樣一個(gè)回調(diào),當(dāng)Observable沒(méi)發(fā)射一項(xiàng)數(shù)據(jù)就會(huì)調(diào)用它一次,包括onNext、onError和 onCompleted
- doOnNext:只有執(zhí)行onNext的時(shí)候會(huì)被調(diào)用
- doOnSubscribe: 當(dāng)觀察者(Sunscriber)訂閱Observable時(shí)就會(huì)被調(diào)用
- doOnUnsubscribe: 當(dāng)觀察者取消訂閱Observable時(shí)就會(huì)被調(diào)用;Observable通過(guò)onError或者onCompleted結(jié)束時(shí),會(huì)反訂閱所有的Subscriber
- doOnCompleted:當(dāng)Observable 正常終止調(diào)用onCompleted時(shí)會(huì)被調(diào)用。
- doOnError: 當(dāng)Observable 異常終止調(diào)用onError時(shí)會(huì)被調(diào)用。
- doOnTerminate: 當(dāng)Observable 終止之前會(huì)被調(diào)用,無(wú)論是正常還是異常終止
- finallyDo: 當(dāng)Observable 終止之后會(huì)被調(diào)用,無(wú)論是正常還是異常終止。
Observable.just(1, 2, 3)
// 只有onNext的時(shí)候才會(huì)被觸發(fā)
.doOnNext(new Action1<Integer>() {
@Override
public void call(Integer item) {
System.out.println("-->doOneNext: " + item);
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.out.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
System.out.println("doOnEach,doOnError------------------------");
Observable.just(1, 2, 3)
// Observable每發(fā)射一個(gè)數(shù)據(jù)的時(shí)候就會(huì)觸發(fā)這個(gè)回調(diào),不僅包括onNext還包括onError和onCompleted
.doOnEach(new Action1<Notification<? super Integer>>() {
@Override
public void call(Notification<? super Integer> notification) {
System.out.println("-->doOnEach: " + notification.getKind() + ":" + notification.getValue());
if ((int) notification.getValue() > 1) {
throw new RuntimeException("Item exceeds maximum value");
}
}
})
// Observable異常終止調(diào)用onError時(shí)會(huì)被調(diào)用
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
System.out.println("-->doOnError: " + throwable.getMessage());
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.out.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
System.out.println("doxxx------------------------");
Observable.just(1, 2, 3).doOnCompleted(new Action0() {
@Override
public void call() {
System.out.println("-->doOnCompleted:正常完成onCompleted"); // 數(shù)據(jù)序列發(fā)送完畢回調(diào)
}
}).doOnSubscribe(() -> System.out.println("-->doOnSubscribe:被訂閱")) // 被訂閱時(shí)回調(diào)
// 反訂閱(取消訂閱)時(shí)回調(diào)。當(dāng)一個(gè)Observable通過(guò)OnError或者OnCompleted結(jié)束的時(shí)候,會(huì)反訂閱所有的Subscriber
.doOnUnsubscribe(() -> System.out.println("-->doOnUnsubscribe:反訂閱"))
// Observable終止之前會(huì)被調(diào)用,無(wú)論是正常還是異常終止
.doOnTerminate(() -> System.out.println("-->doOnTerminate:終止之前"))
// Observable終止之后會(huì)被調(diào)用,無(wú)論是正常還是異常終止
.finallyDo(() -> System.out.println("-->finallyDo:終止之后")).subscribe(new Subscriber<Integer>() {
@Override
public void onNext(Integer item) {
System.out.println("Next: " + item);
}
@Override
public void onError(Throwable error) {
System.out.println("Error: " + error.getMessage());
}
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
});
(25)線程切換SubscribeOn、observeOn:
- 這兩個(gè)操作符對(duì)于Android開(kāi)發(fā)來(lái)說(shuō)非常適用,因?yàn)锳ndroid中只能在主線程中修改UI,耗時(shí)操作不能在主線程中執(zhí)行,
- 所以我們經(jīng)常會(huì)創(chuàng)建新的Thread去執(zhí)行耗時(shí)操作,然后配合Handler修改UI,或者使用AsyncTask。
- RxJava中使用這兩個(gè)操作符能夠讓我們非常方便的處理各種線程問(wèn)題。
- SubscribeOn:指定Observable自身在哪個(gè)調(diào)度器上執(zhí)行(即在那個(gè)線程上運(yùn)行),如果Observable需要執(zhí)行耗時(shí)操作,
- 一般我們可以讓其在新開(kāi)的一個(gè)子線程上運(yùn)行,好比AsyncTask的doInBackground方法。
- observeOn:可以使用observeOn操作符指定Observable在哪個(gè)調(diào)度器上發(fā)送通知給觀察者(調(diào)用觀察者的onNext,onCompleted,onError方法)。
- 一般我們可以指定在主線程中觀察,這樣就可以修改UI,相當(dāng)于AsyncTask的onPreExecute 、onPrograssUpdate和onPostExecute 方法中執(zhí)行
- Schedulers.computation(?) 用于計(jì)算任務(wù),如事件循環(huán)或和回調(diào)處理,不要用于IO操作(IO操作請(qǐng)使用Schedulers.io());默認(rèn)線程數(shù)等于處理器的數(shù)量
- Schedulers.from(executor) 使用指定的Executor作為調(diào)度器
- Schedulers.immediate(?) 在當(dāng)前線程立即開(kāi)始執(zhí)行任務(wù)
- Schedulers.io(?) 用于IO密集型任務(wù),如異步阻塞IO操作,這個(gè)調(diào)度器的線程池會(huì)根據(jù)需要增長(zhǎng);對(duì)于普通的計(jì)算任務(wù),請(qǐng)使用Schedulers.computation();Schedulers.io(?)默認(rèn)是一個(gè)CachedThreadScheduler,很像一個(gè)有線程緩存的新線程調(diào)度器
- Schedulers.newThread(?) 為每個(gè)任務(wù)創(chuàng)建一個(gè)新線程
- Schedulers.trampoline(?) 當(dāng)其它排隊(duì)的任務(wù)完成后,在當(dāng)前線程排隊(duì)開(kāi)始執(zhí)行
System.out.println("currentThread:" + Thread.currentThread().getName());
Observable<Integer> obs = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
System.out.println("on subscrib:" + Thread.currentThread().getName());
subscriber.onNext(1);
subscriber.onCompleted();
}
});
// 在新建子線程中執(zhí)行,在主線程中觀察 AndroidSchedulers.mainThread()
obs.subscribeOn(Schedulers.newThread()).observeOn(Schedulers.newThread())
.subscribe(i -> System.out.println("mainThread-onNext:" + Thread.currentThread().getName()));
System.out.println("-------------------");
obs.delaySubscription(2, TimeUnit.SECONDS).subscribeOn(Schedulers.trampoline()) // 用于計(jì)算任務(wù),如事件循環(huán)或和回調(diào)處理
.observeOn(Schedulers.immediate()) // 在當(dāng)前線程立即開(kāi)始執(zhí)行任務(wù)
.subscribe(i -> System.out.println("immediate-onNext:" + Thread.currentThread().getName()));
try {
Thread.sleep(15000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
三、操作符在Android中的應(yīng)用實(shí)踐
1.線程切換注意事項(xiàng)
subscribeOn()和observeOn()這兩個(gè)操作符在使用的時(shí)候可能弄不清楚,下面操作符使用分類(lèi)圖可以參考一下。
create() , just() , from() 等 -- 事件產(chǎn)生
map() , flapMap() , scan() , filter() 等 -- 事件加工
subscribe() -- 事件消費(fèi)
事件產(chǎn)生:默認(rèn)運(yùn)行在當(dāng)前線程,可以由 subscribeOn() 自定義線程
事件加工:默認(rèn)跟事件產(chǎn)生的線程保持一致, 可以由 observeOn() 自定義線程
事件消費(fèi):默認(rèn)運(yùn)行在當(dāng)前線程,可以有observeOn() 自定義
2.線程的生命周期
在Android開(kāi)發(fā)中生命周期可以使用rxlifecycle作為自動(dòng)生命周期管理。
在app開(kāi)發(fā)中異步線程會(huì)產(chǎn)生內(nèi)存泄漏的問(wèn)題,是所有的異步線程都會(huì)產(chǎn)生,不只是RxJava才有。并且RxJava中
RxJava除了這種自動(dòng)回收以外。還可以使用手動(dòng)取消線程。RxJava有取消訂閱的方法可以使用。
注意一點(diǎn)在已經(jīng)進(jìn)入非主線程的代碼執(zhí)行的時(shí)候,是取消不了發(fā)射的,但是可以取消訂閱就可以解決內(nèi)存泄漏的問(wèn)題了。
3.線程池的使用
RxJava的線程處理是可以配置線程池的
ThreadPoolExecutor executor;
.subscribeOn(Schedulers.from(executor)) //發(fā)射端使用線程池
.observeOn(AndroidSchedulers.mainThread()) //接收端使用主線程
這組線程池的搭配可以替代AsyncTask使用了,也可以與AsyncTask共用一個(gè)線程池來(lái)使用。
全文完
參考資料
https://zhuanlan.zhihu.com/p/21714695
http://blog.jobbole.com/110593/
https://www.zhihu.com/question/28292740
http://blog.csdn.net/womendeaiwoming/article/details/46506017
http://blog.csdn.net/caiwanxia1/article/details/52980999
http://www.jdon.com/reactive.html
http://www.infoq.com/cn/news/2016/01/reactive-basics
http://blog.csdn.net/fly1183989782/article/details/62053973
http://ios.jobbole.com/86815/
http://blog.csdn.net/hjjdehao/article/details/53063879
http://blog.csdn.net/Job_Hesc/article/details/46495281
http://blog.csdn.net/dylanzhuang/article/details/52211313
http://blog.csdn.net/xmxkf/article/details/51658445