RxJava之令人尖叫的操作符

嘿,小伙伴們,今天,我繼續(xù)死磕自己。

寫在前面

昨天發(fā)了第一篇將RxJava入門篇,由于小伙伴們上一篇反響還不錯,讓我很受鼓舞。公眾號后臺有小伙伴給我留言說,希望能在以后的文章里面寫一個我自己總結(jié)的RxJava實(shí)際運(yùn)用的Demo。我當(dāng)然答應(yīng)他了。給自己壓力,就是自己在技術(shù)棧上前進(jìn)的動力!不過不是今天這篇文章,預(yù)計(jì)在本周末會在我的GitHub上面開源一個關(guān)于RxJava,上手使用Demo,歡迎持續(xù)關(guān)注。

子曰:工欲善其事,必先利其器。小伙伴,可以一起帶著這樣的心境,一起走過這幾篇文章的更新吧,先基礎(chǔ)打牢,等到我們?nèi)?shí)踐這門技術(shù)的時候,就更加得心應(yīng)手啦!大家一一起加油,一起升級打怪。

上一篇文章,我介紹了RxJava的一些基礎(chǔ)知識,同時也介紹了map()操作符。當(dāng)然如果你并沒有意愿去使用RxJava我一點(diǎn)也不詫異。畢竟才接觸了這么一點(diǎn)??赐赀@篇文章,我相信你肯定想立即在你的項(xiàng)目中使用RxJava了,這篇文章,將介紹許多RxJava的操作符,RxJava的強(qiáng)大性就來自于它所定義的操作符。

萬年慣例,先來看一個例子:

準(zhǔn)備工作

假設(shè)我有這樣一個方法:

這個方法根據(jù)輸入的字符串返回一個網(wǎng)站的url列表

Observable> query(String text);

現(xiàn)在我希望構(gòu)建一個健壯系統(tǒng),它可以查詢字符串并顯示結(jié)果。根據(jù)上一篇文章的內(nèi)容,我們可能會寫出下面的代碼:

query("Hello,world!")

.subscribe(urls ->{

for(String url : urls){

System.out.println(url);

}

});

這種代碼當(dāng)然是不能容忍的,因?yàn)樯厦娴拇a使我們喪失了變化數(shù)據(jù)流的能力。一旦我們想要更改每一個URL,只能在Subscriber中來做。我們竟然沒有使用如此之酷的map()操作符!

當(dāng)然,我可以使用map操作符,map中輸入的是urls的列表,處理的時候,還是要for each遍歷,一樣很蛋疼。

萬幸,還有Observable.from()方法,它接收一個集合作為輸入,然后每次輸入一個元素給Subscriber:

Observabke.form("url1","url2","url3")

.subscribe(url -> System.out.println(url));

我們來把這個方法使用到剛才的場景:

query("Hello,world!")

.subscribe(urls ->{

Observable.from(urls)

.subscribe(url -> System.out.println(url));

});

看到這里,也許你會說,雖然去掉了for each循環(huán),但是代碼依然看起來很亂。多個嵌套的subscription不僅看起來很丑,代碼難以維護(hù),更嚴(yán)重的是它會破壞某些我們現(xiàn)在還沒講到的RxJava的特性。

改進(jìn)

救世主來臨的時刻,程序猿界總是充滿著善意的愛,它就是flatMap().

Observable.flatMap()接受一個Observable的輸出作為輸入。同時輸出另外一個Observable。直接看代碼:

query("Hello,world!")

.flatMap(new Fun1, Observable>(){

@Override

public Observable call(List urls){

retuen Observable.from(urls);

}

})

.subscribe(url -> System.out.println(url));

這里我貼出了整個函數(shù)代碼,以方便你了解發(fā)生了什么,使用Lambda可以大大簡化代碼長度:

query("Hello,world!")

.flatMap(urls -> Observable.from(urls))

.subscribe(url -> System.out.println(urs));

flatMap是不是看起來很奇怪?為什么它要返回另外一個Observable呢?理解flatMap的關(guān)鍵點(diǎn)在于,flatMap輸出的新的Observable正是我們在Subscriber想要接收的?,F(xiàn)在Subscriber不再收到List,而是收到一些單列的字符串,就像Observable.from()的輸出一樣。

這部分也就是我當(dāng)初學(xué)RxJava的時候最難理解的部分,一旦領(lǐng)悟了,RxJava很對疑問也就有一并解決了。

還可以更好

flatMap()實(shí)在不能更贊了,它可以返回任何它想返回的Observable對象。

比如下面的方法:

1、返回網(wǎng)站的標(biāo)題,如果404了就返回null

2、Observable getTitle(String url);

接著前面的例子,現(xiàn)在我不想打印URL了,而是要打印收到的每個網(wǎng)站的標(biāo)題。問題來了,我的方法每次只能傳入一個URL,并且返回的不是一個String,而是一個輸出String的Observable對象。使用flatMap()可以簡單的解決這個問題。

query("Hello,world!")

.flatMap(urls - >Observable.from(urls))

.flatMap(new Func1>(){

@Override

public Observable call(String url){

return getTitle(url);

}

})

.subscribe(title -> System.out.println(title));

使用Lambda:

query("Hello, world!")

.flatMap(urls - > Observable.from(urls))

.flatMap(url - > getTitle(url))

.subscribe(title - > System.out.println(title));

是不是感覺很不可思議?我竟然能將多個獨(dú)立的返回Observable對象的方法組合在一起!帥呆了!不止這些,我還將兩個API的調(diào)用組合到一個鏈?zhǔn)秸{(diào)用中了。我們可以將任意多個API調(diào)用鏈接起來。大家應(yīng)該都知道同步所有API調(diào)用,然后將所有API調(diào)用的回調(diào)結(jié)果組合成需要展示的數(shù)據(jù),這是一件多么蛋疼的事情。在這里,我們成功的避免了callback (多層嵌套的回調(diào),導(dǎo)致代碼難以閱讀維護(hù))?,F(xiàn)在所有的邏輯都包裝成了這種簡單的響應(yīng)式調(diào)用。

豐富的操作符

目前為止,我們已經(jīng)接觸了兩個操作符,RxJava中還有更多的操作符,那么,我們?nèi)绾问褂闷渌僮鞣麃砀倪M(jìn)我們的代碼呢?

getTitle()返回null如果url 不存在。我們不想輸出 “null” ,那么我們可以從返回的title列表中過濾掉null 值!

query("Hello,world!")

.flatMap(urls - > Observable.from(urls))

.flatMap(ur; - > getTitle(url))

.filter(title - > title !=null)

.subscribe(title - > System.out.println(title));

filter()輸出和輸入相同的元素,并且會過濾掉那些不滿足檢查條件的。

如果我們只想要最多5個結(jié)果:

query("Hello,world!")

.flatMap(urls - > Observable.from(urls))

.flatMap(url - > getTitle(url))

.filter(title - > title! =null)

.take(5)

.subscribe(title - > System.out.println(title));

take()輸出最多指定數(shù)量的結(jié)果。

如果我們在打印之前,把每個標(biāo)題保存到磁盤:

query("Hello,world!")

.flatMap(urls - > Observable.form(urls))

.flatMap(url - > getTitle(url))

.flatMap(title - > title !=null)

.take(5)

.doOnNext(title - > saveTitle(title))

.subscribe(title - > System.out.println(title));

doOnNext()允許我們在每次輸出一個元素之前做一些額外的事情,比如這里的保存標(biāo)題。小伙伴們,看到這里操作數(shù)據(jù)是多么簡單了嗎?你可以添加任意多的操作,并且不會搞亂你的代碼。

RxJava包含了大量的操作符。操作符的數(shù)量是有點(diǎn)嚇人,但是很值得你挨個去看一下,這樣你可以知道哪些操作符可以使用。弄懂這些操作符可能會花一些時間,但是一旦弄懂了,你就完全掌握了RxJava的威力了。

總結(jié)

好吧,如果你是一個懷疑主義者,并且很難被說服,那么為什么要關(guān)心這些操作符呢?

因?yàn)椴僮鞣梢詫?shù)據(jù)流做任何操作。

將一系列的操作符鏈接起來就可以完成復(fù)雜的邏輯。代碼被分解成一系列可以組合的片段。這就是響應(yīng)式函數(shù)編程的魅力所在。用的越多,將會越多的改變你的編程思維。

另外,RxJava也使我們處理數(shù)據(jù)的方式變得簡單。再最后一個例子里,我們調(diào)用了兩個API,對API返回的數(shù)據(jù)進(jìn)行了處理,然后保存到磁盤。但是我們的Subscriber并不知道這些,它只是認(rèn)為自己在接收一個Observable對象。良好的封裝性也帶來了編碼的便利!

嘿,小伙伴們,看到這里是不是覺得對RxJava相見恨晚呢?我現(xiàn)在就有這種感覺!

在我的公眾號的下一篇文章里,我會繼續(xù)介紹RxJava的另外一些很酷的特性,比如錯誤的處理和并發(fā),不過,這些特性不會直接用來處理數(shù)據(jù)。

更多內(nèi)容請關(guān)注我的個人微信公眾號:前端開發(fā)技術(shù)棧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容