RxJava常用操作符

碼個蛋發表於2016-09-19

RxJava 操作符

閱讀本文前請先了解 RxJava 的基本使用。

參考文件:


1 Observable 的建立

1.1 from( )

轉換集合為一個每次發射集合中一個元素的 Observable 物件。可用來遍歷集合。

方法列表:

栗子:

// 1. 遍歷集合
Observable<String> observable = Observable.from(new String[]{"hello", "hi"});複製程式碼
// 2. 使用 Future 建立 Observable,Future 表示一個非同步計算的結果。
FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
    @Override
    public String call() throws Exception {
        // TODO 執行非同步操作並返回資料
        return "hihi";
    }
});

Scheduler.Worker worker = Schedulers.io().createWorker();
worker.schedule(new Action0() {
    @Override
    public void call() {
        futureTask.run();
    }
});

Observable<String> observable = Observable.from(futureTask);複製程式碼

1.2 just( )

轉換一個或多個 Object 為依次發射這些 Object 的 Observable 物件。

方法列表:

栗子:

Observable<String> observable = Observable.just("hello");

// 使用 just() 遍歷幾個元素
Observable<String> observable = Observable.just("hello", "hi", "...");

// 使用 from() 方法遍歷,效果和 just() 一樣。
String[] stringArrs = new String[]{"hello", "hi", "..."};
Observable<String> observable = Observable.from(stringArrs);複製程式碼

just() 方法可傳入 1~10 個引數,也就說當元素個數小於等於 10 的時候既可以使用 just() 也可以使用 from(),否則只能用 from() 方法。

1.3 create( )

返回一個在被 OnSubscribe 訂閱時執行特定方法的 Observable 物件。

方法列表:

栗子:

Observable.OnSubscribe<String> onSubscribe = new Observable.OnSubscribe< String >() {
    @Override
    public void call(Subscriber<? super String > subscriber) {
         // onNext() 方法可執行多次
        subscribe.onNext("hello");
        subscribe.onCompleted();
    }
};
Observable<Object> observable = Observable.create(onSubscribe);複製程式碼

此方法不常用,大多數時候都是使用 just( )form( ) 等方法,如上面那串程式碼就可以寫成:

Observable<Object> observable = Observable.just("hello");複製程式碼

1.4 interval( )

返回一個每隔指定的時間間隔就發射一個序列號的 Observable 物件,可用來做倒數計時等操作。

方法列表:

栗子:

// 每隔 1 s 傳送一個序列號,序列號從 0 開始,每次累加 1。
Observable<Long> observable = Observable.interval(1, TimeUnit.SECONDS);複製程式碼

1.5 timer( )

建立一個在指定延遲時間後發射一條資料( 固定值:0 )的 Observable 物件,可用來做定時操作。

方法列表:

  • [public static Observable<Long> timer(long delay, TimeUnit unit)][23]

23)

栗子:

// 定時 3 s
Observable<Long> observable = Observable.timer(3, TimeUnit.SECONDS);複製程式碼

1.6 range( )

建立一個發射指定範圍內的連續整數的 Observable 物件。

方法列表:

栗子:

// 依次發射 5、6、7
Observable<Integer> observable = Observable.range(5, 3);複製程式碼

1.7 empty()

建立一個不發射任何資料就發出 onCompleted() 通知的 Observable 物件。

方法列表:

栗子:

// 發出一個 onCompleted() 通知
Observable<Object> observable = Observable.empty();複製程式碼

1.8 error( )

建立不發射任何資料就發出 onError 通知的 Observable 物件。

方法列表:

栗子:

// 發出一個 onError() 通知
Observable<Object> observable = Observable.error(new Throwable("message"));複製程式碼

1.9 never()

建立一個不發射任何資料和通知的 Observable 物件。

方法列表:

栗子:

Observable<Object> observable = Observable.never();複製程式碼

1.10 defer( )

在訂閱的時候才會建立 Observable 物件;每一次訂閱都建立一個新的 Observable 物件。

方法列表:

栗子:

Observable<String> observable = Observable.defer(new Func0<Observable<String>>() {
    @Override
    public Observable<String> call() {
        return Observable.just("string");
    }
});複製程式碼

2 重做

2.1 repeat( )

使Observable 物件在發出 onNext() 通知之後重複發射資料。重做結束才會發出 onComplete() 通知,若重做過程中出現異常則會中斷併發出 onError() 通知。

方法列表:

栗子:

Observable<String> observable = Observable.just("string");
// 無限重複執行
observable.repeat();
// 重複執行 5 次
observable.repeat(5);複製程式碼

2.2 repeatWhen( )

使Observable 物件在發出 onNext() 通知之後有條件的重複發射資料。重做結束才會發出 onCompleted() 通知,若重做過程中出現異常則會中斷併發出 onError() 通知。

方法列表:

栗子:

observable.repeatWhen(new Func1<Observable<? extends Void>, Observable<?>>() {
    @Override
    public Observable<?> call(Observable<? extends Void> observable) {
        // 重複 3 次, 每次間隔 1 s
        return observable.zipWith(Observable.range(1, 3), new Func2<Void, Integer, Integer>() {
            @Override
            public Integer call(Void aVoid, Integer integer) {
                return integer;
             }
        }).flatMap(integer -> Observable.timer(1, TimeUnit.SECONDS));
    }
});複製程式碼

3 重試

3.1 retry( )

在執行 Observable物件的序列出現異常時,不直接發出 onError() 通知,而是重新訂閱該 Observable物件,直到重做過程中未出現異常,則會發出 onNext()onCompleted() 通知;若重做過程中也出現異常,則會繼續重試,直到達到重試次數上限,超出次數後發出最新的 onError() 通知。

方法列表:

栗子:

Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        System.out.println(".......");
        int a = 1 / 0;
        subscriber.onNext(a);
        subscriber.onCompleted();
    }
});
// 無限次的重試
observable.retry();
// 重試 3 次
observable.retry(3);
// 使用謂語函式決定是否重試
observable.retry(new Func2<Integer, Throwable, Boolean>() {
    @Override
    public Boolean call(Integer integer, Throwable throwable) {
        // 引數 integer 是訂閱的次數; 引數 throwable 是丟擲的異常
        // 返回值為 true 表示重試, 返回值為 false 表示不重試
        return false;
    }
});複製程式碼

3.2 retryWhen( )

作用: 有條件的執行重試。

方法列表:

栗子:

// 重試 3 次,每次間隔 1 s
observable.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
    @Override
    public Observable<?> call(Observable<? extends Throwable> observable) {
        return observable.zipWith(Observable.range(1, 3), new Func2<Throwable, Integer, Object>() {
            @Override
            public Object call(Throwable throwable, Integer integer) {
                return integer;
            }
        }).flatMap(new Func1<Object, Observable<?>>() {
            @Override
            public Observable<?> call(Object o) {
                return Observable.timer(1, TimeUnit.SECONDS);
            }
        });
    }
});複製程式碼

4 變換

4.1 map( )

把源 Observable 發射的元素應用於指定的函式,併傳送該函式的結果。

方法列表:

栗子:

Observable.just(2)
        .map(new Func1<Integer, String>() {
            @Override
            public String call(Integer integer) {
                return String.valueOf(String.format("原始資料的兩倍為: %s", integer * 2));
            }
        });複製程式碼

4.2 flatMap( )

轉換源 Observable 物件為另一個 Observable 物件。

方法列表:

栗子:

Observable.just(2)
        .flatMap(new Func1<Integer, Observable<Long>>() {
            @Override
            public Observable<Long> call(Integer integer) {
                // 轉換為一個定時 integer 秒的 Observable 物件
                return Observable.timer(integer, TimeUnit.SECONDS);
            }
        });複製程式碼

5 過濾

5.1 filter( )

只發射滿足指定謂詞的元素。

方法列表:

栗子:

Observable.just(-1, -2, 0, 1, 2)
        .filter(new Func1<Integer, Boolean>() {
            @Override
            public Boolean call(Integer integer) {
                return integer > 0;
            }
        });複製程式碼

5.2 first( )

返回一個僅僅發射源 Observable 發射的第一個[滿足指定謂詞的]元素的 Observable,如果如果源 Observable 為空,則會丟擲一個 NoSuchElementException

方法列表:

栗子:

// 發射第一個元素
Observable.just(-1, -2, 0, 1, 2).first();

// 發射滿足條件的第一個元素
Observable.just(-1, -2, 0, 1, 2)
        .first(new Func1<Integer, Boolean>() {
            @Override
            public Boolean call(Integer integer) {
                return integer > 0;
            }
        });

// 會丟擲 NoSuchElementException 異常
Observable.empty().first();複製程式碼

5.3 last( )

返回一個僅僅發射源 Observable 發射的倒數第一個[滿足指定謂詞的]元素的 Observable,如果如果源 Observable 為空,則會丟擲一個 NoSuchElementException

方法列表:

栗子:

// 發射倒數第一個元素
Observable.just(-1, -2, 0, 1, 2).first();

// 發射滿足條件的倒數第一個元素
Observable.just(-1, -2, 0, 1, 2)
        .first(new Func1<Integer, Boolean>() {
            @Override
            public Boolean call(Integer integer) {
                return integer < 0;
            }
        });

// 會丟擲 NoSuchElementException 異常
Observable.empty().last();複製程式碼

5.4 skip( )

跳過前面指定數量或指定時間內的元素,只發射後面的元素。

方法列表:

栗子:

Observable.just(-1, -2, 0, 1, 2)
        .skip(2) // 跳過前兩條資料複製程式碼

5.5 skipLast( )

跳過前面指定數量或指定時間內的元素,只發射後面的元素。指定時間時會延遲源 Observable 發射的任何資料。

方法列表:

栗子:

Observable.just(-1, -2, 0, 1, 2)
        .skip(2) // 跳過後兩條資料複製程式碼

5.6 take( )

只發射前面指定數量或指定時間內的元素。

方法列表:

栗子:

Observable.just(-1, -2, 0, 1, 2).take(3); // 只發射前三條資料複製程式碼

5.7 takeLast( )

只發射後面指定數量或指定時間內的元素。指定時間時會延遲源 Observable 發射的任何資料。

方法列表:

栗子:

Observable.just(-1, -2, 0, 1, 2).takeLast(3); // 只發射後三條資料複製程式碼

5.8 sample( )

定期發射 Observable 發射的最後一條資料。

方法列表:

栗子:

Observable.interval(300, TimeUnit.MILLISECONDS)
        .sample(2, TimeUnit.SECONDS)複製程式碼

5.9 elementAt( )

只發射指定索引的元素。

方法列表:

栗子:

Observable.just(-1, -2, 0, 1, 2).elementAt(2); // 發射索引為 2 的資料複製程式碼

5.10 elementAtOrDefault( )

只發射指定索引的元素,若該索引對應的元素不存在,則發射預設值。

方法列表:

栗子:

Observable.just(-1, -2, 0, 1, 2).elementAtOrDefault(9, -5); // 發射索引為 9的資料,若不存在,則發射 -5複製程式碼

5.11 ignoreElements( )

不發射任何資料,直接發出 onCompleted() 通知。

方法列表:

栗子:

Observable.just(-1, -2, 0, 1, 2).ignoreElements()複製程式碼

5.12 distinct( )

過濾重複的元素,過濾規則是:只允許還沒有發射過的元素通過。

方法列表:

栗子:

// 直接過濾
Observable.just(-1, -2, 0, 1, 2, 1).distinct();

// 通過生成的 key 值過濾
Observable.just(-1, -2, 0, 1, 2, 1).distinct(new Func1<Integer, Integer>() {
    @Override
    public Integer call(Integer integer) {
        // 隨機生成 key
        return integer * (int)(Math.random() * 10);
    }
});複製程式碼

5.13 debounce( )

Observable 每產生結果後,如果在規定的間隔時間內沒有產生新的結果,則發射這個結果,否則會忽略這個結果。該操作符會過濾掉髮射速率過快的資料項。

方法列表:

栗子:

Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        try {
            //產生結果的間隔時間分別為100、200、300...900毫秒
            for (int i = 1; i < 10; i++) {
                subscriber.onNext(i);
                Thread.sleep(i * 100);
            }
            subscriber.onCompleted();
        } catch (Exception e) {
            subscriber.onError(e);
        }
    }
});
observable.debounce(400, TimeUnit.MILLISECONDS)  // 超時時間為400毫秒複製程式碼

該栗子產生結果為:依次列印5、6、7、8。

附:功能實現

延時遍歷

// 遍歷
Observable<Integer> traverseObservable = Observable.just(3, 4, 5, 6);
// 計時
Observable<Long> intervalObservable = Observable.interval(1, TimeUnit.SECONDS);

Func2<Long, Integer, Integer> func2 = new Func2<Long, Integer, Integer>() {
    @Override
    public Integer call(Long aLong, Integer integer) {
        return integer;
    }
};

intervalObservable.zipWith(traverseObservable, func2)
        .toBlocking()
        .subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }

           @Override
           public void onError(Throwable e) {
               e.printStackTrace();
            }

            @Override
            public void onNext(Integer integer) {
                System.out.println(integer);
            }
        });複製程式碼

倒數計時

int startTime = 10;

Observable.interval(0, 1, TimeUnit.SECONDS)
        .take(startTime + 1) // 接收 startTime + 1 次
        .map(new Func1<Long, Long>() {
            @Override
            public Long call(Long time) {
                // 1 2 3...轉換為...3 2 1
                return startTime - time;
            }
        })
        .toBlocking()
        .subscribe(new Subscriber<Long>() {
            @Override
            public void onCompleted() {
                System.out.println("倒數計時結束");
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("倒數計時出現異常");
                e.printStackTrace();
            }

            @Override
            public void onNext(Long aLong) {
                System.out.println(String.format("倒數計時: %s s", aLong));
            }
       });複製程式碼

歡迎大家關注我的簡書Github

相關文章