理解RxJava:(二)Operator,Operator

第一部分,我講解了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。有不少尚未學到。其餘的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!這超出了本文的討論範圍。可是隻要你想你就能作到。

So What?

若是你是個懷疑論者。你會問爲何要關注這些operators?

關鍵點3 Operators讓你能對數據流作任何事

惟一的限制就是你本身。

你能夠處理複雜的邏輯,從使用簡單的operators鏈開始。它將你的代碼打破爲可重組的零碎東西。這就是函數響應式編程。你用的越多,就越能改變你編程的思惟。

另外,想一想咱們的代碼一轉換消費起來變得多容易。最後的例子,咱們調用了兩次API,操做數據,而後存儲。可是Subscriber並不知道這些。它想的僅僅是消費Observable<String>。封裝讓編程更簡單。

在第三部分,咱們將繼續瞭解RxJava的特性。好比錯誤處理和併發,和操做數據沒有直接聯繫。

本文翻譯自Grokking RxJava, Part 2: Operator Operator,著做權歸原做者danlew全部。譯文由JohnTsai翻譯。轉載請註明出處,並保留此段聲明。

相關文章
相關標籤/搜索