在第一部分,我講解了RxJava的基本結構,也介紹了map()
操做。然而,我能理解你仍舊不會選擇使用Rxjava——你仍然還有不少東西沒有學到。可是這個狀況將很快獲得改變。Rxjava一大部分的能力是由於其中的operators。java
讓咱們經過一個例子來向大家介紹更多的operators。git
假設我有一個這樣的方法:github
//返回一個基於文本查詢網站連接的列表 Observable<List<String>> query(String text);
我想要構建一個搜索文本和顯示結果的強健系統。基於上篇文章咱們學到的,如下是咱們立刻想到的:編程
query("Hello, world!") .subscribe(urls -> { for (String url : urls) { System.out.println(url); } });
這個答案讓人很是不滿意,由於失去了轉換數據流的能力。若是我想要修改每一個URL,只能在每一個Subscriber
裏面修改。這就違背了使用map()
操做的初衷。併發
我能夠爲ulrs->urls建立一個map()
,可是每一個map()
的內部都有一個for-each循環。哎喲。ide
有一個方法,Observable.from()
,輸入一些items,而後每次發出一個:函數
Observable.from("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循環,可是代碼顯得很混亂。如今變成了多個嵌套的subscriptions了。除了代碼醜陋以及難以修改外,也違背了RxJava的一些原則。網站
屏住你的呼吸,由於你見到了你的救世主:flatMap()
。url
Observable.flatMap()
獲取一個Observable
的返回值,將值發給另外一個取代它的Observable
。以下:
query("Hello, world!") .flatMap(new Func1<List<String>, Observable<String>>() { @Override public Observable<String> call(List<String> urls) { return Observable.from(urls); } }) .subscribe(url -> System.out.println(url));
我寫成完整的方法是爲了你能看到發生了什麼,可是用 lambda表達式簡寫看起來很棒:
query("Hello, world!") .flatMap(urls -> Observable.from(urls)) .subscribe(url -> System.out.println(url));
flatMap()
(看起來)很怪,對嗎?爲何返回另外一個Observable
?核心概念是新的Observable
返回的正是Subscriber
所觀察的。它不接收List<String>
——它接收Observable.from()
返回的一系列的單獨的Strings
。
我強調這個觀點幾遍都不足夠:flatMap()
能返回任意想要的Observable
。
假設我又有一個這樣的方法:
// 返回網站的標題,如果404則返回null Observable<String> getTitle(String URL);
本來是打印URL,如今我想要打印接收的每一個網站的標題。可是有些問題:個人方法只對每次一個URL有效,並且它返回的不是String,它返回的是發出String的Observable
。
有了flatMap()
,解決這個問題很簡單。在把一系列的URL分開爲單獨的items後,我能夠在flatMap()
方法中對於每一個URL使用getTitle()
,在它到達Subscriber
前。
query("Hello, world!") .flatMap(urls -> Observable.from(urls)) .flatMap(new Func1<String, Observable<String>>() { @Override public Observable<String> 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));
很酷,對吧?我把幾個返回Observable
方法組合在一塊兒。
不只僅於此,我還將兩個API調用組合在一條方法鏈上了。大家知道維持全部的API調用同步,必須在數據展現前將它們的回調寫在一塊兒,是有多痛苦?咱們不用再忍受嵌套回調了。全部的邏輯都包在簡短的響應式調用中了。
到目前爲止,咱們僅僅學習了兩種operators。有不少尚未學到。其餘的operators能怎樣改善咱們的代碼呢?
getTitle()
在URL404的時候返回null。咱們不想要輸出"null"
。如下代碼顯示咱們能夠過濾掉null:
query("Hello, world!") .flatMap(urls -> Observable.from(urls)) .flatMap(url -> getTitle(url)) .filter(title -> title != null) .subscribe(title -> System.out.println(title));
filter()
方法發出和它們接收到的一樣的item,只在經過了boolean檢查的狀況下。
如今咱們只想要最多顯示5個結果:
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()
最多發出指定數量的item(若是少於5個標題,它會提早中止)。
如今咱們想要存儲每一個標題到磁盤上:
query("Hello, world!") .flatMap(urls -> Observable.from(urls)) .flatMap(url -> getTitle(url)) .filter(title -> title != null) .take(5) .doOnNext(title -> saveTitle(title)) .subscribe(title -> System.out.println(title));
doOnNext()
讓咱們能夠在每次一個item被髮出以前,添加額外的行爲。
看操做數據流多麼簡單。你能夠繼續對數據添加操做而不會弄糟任何事情。
RxJava有很是多的Operators。這麼多operators讓咱們被嚇到,可是值得查閱一遍以知道哪一個對咱們有用。消化這些操做會花費點時間,可是咱們能信手拈來的時候就能感覺到Rxjava真正的強大。
以上都是官方提供的,咱們甚至能夠自定義operators!這超出了本文的討論範圍。可是隻要你想你就能作到。
若是你是個懷疑論者。你會問爲何要關注這些operators?
惟一的限制就是你本身。
你能夠處理複雜的邏輯,從使用簡單的operators鏈開始。它將你的代碼打破爲可重組的零碎東西。這就是函數響應式編程。你用的越多,就越能改變你編程的思惟。
另外,想一想咱們的代碼一轉換消費起來變得多容易。最後的例子,咱們調用了兩次API,操做數據,而後存儲。可是Subscriber
並不知道這些。它想的僅僅是消費Observable<String>
。封裝讓編程更簡單。
在第三部分,咱們將繼續瞭解RxJava的特性。好比錯誤處理和併發,和操做數據沒有直接聯繫。
本文翻譯自Grokking RxJava, Part 2: Operator Operator,著做權歸原做者danlew全部。譯文由JohnTsai翻譯。轉載請註明出處,並保留此段聲明。