RxJava操作符(02-創建操作)

版權聲明:本文爲openXu原創文章【openXu的博客】,未經博主允許不得以任何形式轉載

目錄:


  在上一篇博客中我們初步體驗了Rxjava的使用,領略了RxJava對於異步操作流編碼的簡潔風格,接下來的一系列博客,我們主要學習RxJava中的操作符,也就是RxJava的一些API,由於是學習API,我在示例代碼中儘量少用Lambda表達式等簡潔方式,這樣方便查看類型,有助於瞭解API,等熟悉操作符之後就可以使用簡化代碼了。學習操作符會有一些枯燥,只要堅持下去,相信你不會後悔。這篇博客我們學習Observable的創建操作符。

1. Create

  • 使用Create操作符從頭開始創建一個Observable,給這個操作符傳遞一個接受觀察者作爲參數的函數,我們需要實現call方法發射一些數據,並恰當的調用觀察者的onNext,onError和onCompleted方法;
  • 一個形式正確的有限Observable必須嘗試調用觀察者的onCompleted正好一次或者它的onError正好一次,而且此後不能再調用觀察者的任何其它方法;
  • 建議你在傳遞給create方法的函數中檢查觀察者的isUnsubscribed狀態,以便在沒有觀察者的時候,讓你的Observable停止發射數據或者做昂貴的運算;
  • create方法默認不在任何特定的調度器上執行。

    這裏寫圖片描述

示例代碼:

//訂閱者
Subscriber subscriber= new Subscriber<Integer>() {
    @Override
    public void onNext(Integer item) {
        Log.d(TAG, "Next: " + item);
    }
    @Override
    public void onError(Throwable error) {
        Log.d(TAG, "Error: " + error.getMessage());
    }
    @Override
    public void onCompleted() {
        Log.d(TAG, "Sequence complete.");
    }
};
//create方法默認不在任何特定的調度器上執行。
Observable observable = Observable.create(new Observable.OnSubscribe<Integer>() {
    //當Observable.subscribe被調用時(有訂閱者時)執行call方法
    @Override
    public void call(Subscriber<? super Integer> observer) {
        try {
            //檢查觀察者的isUnsubscribed狀態,以便在沒有觀察者的時候,讓Observable停止發射數據或者做昂貴的運算
            for (int i = 1; i < 5; i++) {
                if(i == 4){
                    //取消訂閱 (Unsubscribing),調用這個方法表示你不關心當前訂閱的Observable了,
                    //因此Observable可以選擇停止發射新的數據項(如果沒有其它觀察者訂閱)。
                    subscriber.unsubscribe();
                }
                if (!observer.isUnsubscribed()) {
                    observer.onNext(i);
                }
            }
            if (!observer.isUnsubscribed()) {
                observer.onCompleted();
            }
        } catch (Exception e) {
            observer.onError(e);
        }
    }
} );
//訂閱
observable.subscribe(subscriber);

輸出:

Next: 1
Next: 2
Next: 3

2. Defer

  • 直到有觀察者訂閱時才創建Observable,並且爲每個觀察者創建一個新的Observable
  • Defer操作符會一直等待直到有觀察者訂閱它,然後它使用Observable工廠方法生成一個Observable。它對每個觀察者都這樣做,因此儘管每個訂閱者都以爲自己訂閱的是同一個Observable,事實上每個訂閱者獲取的是它們自己的單獨的數據序列。
  • 在某些情況下,等待直到最後一分鐘(就是知道訂閱發生時)才生成Observable可以確保Observable包含最新的數據。
  • 這個操作符接受一個你選擇的Observable工廠函數作爲單個參數。這個函數沒有參數,返回一個Observable。
  • defer方法默認不在任何特定的調度器上執行。
        這裏寫圖片描述

示例代碼:

  Defer操作符只有當觀察者訂閱時才創建一個新的Observable對象,每個觀察者訂閱的時候都會得到一個新的(不是同一個)Observable對象,以確保Observable包含最新的數據。下面的例子中用Just操作符作爲對比,分別來返回當前的時間:可以發現Defer操作符每次返回的都是最新的時間值。

private Observable<Date> deferObservable;
private Observable<Date> justObservable;
private void op_Defer(){
    if(deferObservable == null) {
        deferObservable = Observable.defer(() -> Observable.just(new Date()));
    }
    deferObservable.subscribe(date ->  {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        Log.v(TAG, "defer:" + sdf.format(date));
    });
    if(justObservable == null){
        justObservable = Observable.just(new Date());
    }
    justObservable.subscribe(date ->  {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        Log.v(TAG, "just:" + sdf.format(date));
    });
}

輸出:

defer:02:40:53
just:02:40:53
defer:02:40:55 
just:02:40:53
defer:02:40:57
just:02:40:53

3. Empty/Never/Throw

  • Empty:創建一個不發射任何數據但是正常終止的Observable
  • Never:創建一個不發射數據也不終止的Observable
  • Throw :創建一個不發射數據以一個錯誤終止的Observable

  這三個操作符生成的Observable行爲非常特殊和受限。測試的時候很有用,有時候也用於結合其它的Observables,或者作爲其它需要Observable的操作符的參數。error操作符需要一個Throwable參數,你的Observable會以此終止。這些操作符默認不在任何特定的調度器上執行,但是empty和error有一個可選參數是Scheduler,如果你傳遞了Scheduler參數,它們會在這個調度器上發送通知。

示例代碼:

//enpty默認實現call,只調用onCompleted:public void call(Subscriber<? super Object> child) {child.onCompleted();}
Observable.empty().subscribe(new Subscriber<Object>() {
    @Override
    public void onNext(Object item) {
        Log.d(TAG, "Enpty:Next: " + item);
    }
    @Override
    public void onError(Throwable error) {
        Log.d(TAG, "Enpty:Error: " + error.getMessage());
    }
    @Override
    public void onCompleted() {
        Log.d(TAG, "Enpty:Sequence complete.");
    }
});

//Never:創建一個不發射數據也不終止的Observable(不會調用訂閱者的任何方法)
Observable.never().subscribe(new Subscriber<Object>() {
    @Override
    public void onNext(Object item) {
        Log.d(TAG, "Nerver:Next: " + item);
    }
    @Override
    public void onError(Throwable error) {
        Log.d(TAG, "Nerver:Error: " + error.getMessage());
    }
    @Override
    public void onCompleted() {
        Log.d(TAG, "Nerver:Sequence complete.");
    }
});

//Error:創建一個不發射數據以一個錯誤終止的Observable(只會調用onError)
Observable.error(new Throwable("just call onError")).subscribe(new Subscriber<Object>() {
    @Override
    public void onNext(Object item) {
        Log.d(TAG, "Error:Next: " + item);
    }
    @Override
    public void onError(Throwable error) {
        Log.d(TAG, "Error:Error: " + error.getMessage());
    }
    @Override
    public void onCompleted() {
        Log.d(TAG, "Error:Sequence complete.");
    }
});

輸出:

Enpty:Sequence complete.

Error:Error: just call onError

4. From

  • Javadoc: from(array)
  • Javadoc: from(Iterable)
  • Javadoc: from(Future)
  • Javadoc: from(Future,Scheduler)
  • Javadoc: from(Future,timeout, timeUnit)
  • 將一個Iterable, 一個Future, 或者一個數組轉換成一個Observable。
  • 在RxJava中,from操作符可以轉換Future、Iterable和數組。對於Iterable和數組,產生的Observable會發射Iterable或數組的每一項數據
  • 對於Future,它會發射Future.get()方法返回的單個數據。from方法有一個可接受兩個可選參數的版本,分別指定超時時長和時間單位。如果過了指定的時長Future還沒有返回一個值,這個Observable會發射錯誤通知並終止。
  • from默認不在任何特定的調度器上執行。然而你可以將Scheduler作爲可選的第二個參數傳遞給Observable,它會在那個調度器上管理這個Future。

    這裏寫圖片描述

示例代碼:

  From操作符用來將某個對象轉化爲Observable對象,並且依次將其內容發射出去。這個類似於just,但是just會將這個對象整個發射出去。比如說一個含有10個數字的數組,使用from就會發射10次,每次發射一個數字,而使用just會發射一次來將整個的數組發射出去。

Integer[] items = { 0, 1, 2, 3, 4, 5 };
Observable myObservable = Observable.from(items);
myObservable.subscribe(
        new Action1<Integer>() {
            @Override
            public void call(Integer item) {
                Log.d(TAG, item+"");
            }
        },
        new Action1<Throwable>() {
            @Override
            public void call(Throwable error) {
                Log.d(TAG,"Error encountered: " + error.getMessage());
            }
        },
        new Action0() {
            @Override
            public void call() {
                Log.d(TAG,"Sequence complete");
            }
        }
);

輸出:

0
1
2
3
4
5
Sequence complete

5. Interval

  • Interval操作符返回一個Observable,它按固定的時間間隔發射一個無限遞增的整數序列

  • 它接受一個表示時間間隔的參數和一個表示時間單位的參數

  • 還有一個版本的interval返回一個Observable,它在指定延遲之後先發射一個零值,然後再按照指定的時間間隔發射遞增 的數字。這個版本的interval在RxJava 1.0.0中叫做timer,但是那個方法已經不建議使用了,因爲一個名叫interval的操作符有同樣的功能。

  • interval默認在computation調度器上執行。你也可以傳遞一個可選的Scheduler參數來指定調度器。

    • Javadoc: interval(long,TimeUnit)
    • Javadoc: interval(long,TimeUnit,Scheduler)
          這裏寫圖片描述

示例代碼:

private void op_Interval(TextView textView){
    //以秒爲單位,每隔1秒發射一個數據
    Observable.interval(1, TimeUnit.SECONDS)
    //interva operates by default on the computation Scheduler,so observe on main Thread
    //如果需要更新view,要在主線程中訂閱
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<Long>() {
        @Override
        public void onCompleted() {
            Log.d(TAG,"onCompleted" );
        }
        @Override
        public void onError(Throwable e) {
            Log.d(TAG,"onError:" + e.getMessage());
        }
        @Override
        public void onNext(Long aLong) {
            Log.d(TAG,"interval:" + aLong);
            textView.setText("Interval:"+aLong);
        }
    });
}

輸出:

interval:0
interval:1
interval:2
interval:3
interval:4
interval:5
...

6. Just

  • Just將單個數據轉換爲發射那個數據的Observable,創建一個發射指定值的Observable
  • Just類似於From,但是From會將數組或Iterable的素具取出然後逐個發射,而Just只是簡單的原樣發射,將數組或Iterable當做單個數據
  • 注意:如果你傳遞null給Just,它會返回一個發射null值的Observable。不要誤認爲它會返回一個空Observable(完全不發射任何數據的Observable),如果需要空Observable你應該使用Empty操作符
  • RxJava將這個操作符實現爲just函數,它接受一至九個參數,返回一個按參數列表順序發射這些數據的Observable。

    這裏寫圖片描述

示例代碼:

Observable.just(1, 2, 3)
        .subscribe(new Subscriber<Integer>() {
            @Override
            public void onNext(Integer item) {
                 Log.d(TAG,"Next: " + item);
            }

            @Override
            public void onError(Throwable error) {
                System.err.println("Error: " + error.getMessage());
            }

            @Override
            public void onCompleted() {
                 Log.d(TAG,"Sequence complete.");
            }
        });

輸出:

Next: 1
Next: 2
Next: 3
Sequence complete.

7. Range

  • Range操作符創建一個發射指定範圍的整數序列的Observable,你可以指定範圍的起始和長度。

  • 它接受兩個參數,一個是範圍的起始值,一個是範圍的數據的數目。如果你將第二個參數設爲0,將導致Observable不發射任何數據(如果設置爲負數,會拋異常)

  • range默認不在任何特定的調度器上執行。有一個變體可以通過可選參數指定Scheduler。

    • Javadoc: range(int,int)
    • Javadoc: range(int,int,Scheduler)

    這裏寫圖片描述

示例代碼:

Observable.range(100, 6).subscribe(new Subscriber<Integer>() {
    @Override
    public void onNext(Integer item) {
        Log.d(TAG,"Next: " + item);
    }
    @Override
    public void onError(Throwable error) {
        System.err.println("Error: " + error.getMessage());
    }
    @Override
    public void onCompleted() {
        Log.d(TAG,"Sequence complete.");
    }
});

輸出:

Next: 100
Next: 101
Next: 102
Next: 103
Next: 104
Next: 105
Sequence complete.

8. Repeat

  • Repeat重複地發射數據。某些實現允許你重複的發射某個數據序列,還有一些允許你限制重複的次數。
  • 它不是創建一個Observable,而是重複發射原始Observable的數據序列,這個序列或者是無限的,或者通過repeat(n)指定重複次數。
  • repeat操作符默認在trampoline調度器上執行。有一個變體可以通過可選參數指定Scheduler

    這裏寫圖片描述

示例代碼:

//重複5次發送數據1
Observable.just(1).repeat(5).subscribe(new Subscriber<Integer>() {
    @Override
    public void onNext(Integer item) {
        Log.d(TAG,"Next: " + item);
    }
    @Override
    public void onError(Throwable error) {
        System.err.println("Error: " + error.getMessage());
    }
    @Override
    public void onCompleted() {
        Log.d(TAG,"Sequence complete.");
    }
});

輸出:

Next: 1
Next: 1
Next: 1
Next: 1
Next: 1
Sequence complete.

9. Timer

  • Timer操作符創建一個在給定的時間段之後返回一個特殊值的Observable

  • timer返回一個Observable,它在延遲一段給定的時間後發射一個簡單的數字0

  • timer操作符默認在computation調度器上執行。有一個變體可以通過可選參數指定Scheduler

    • Javadoc: timer(long,TimeUnit))
    • Javadoc: timer(long,TimeUnit,Scheduler))

    這裏寫圖片描述

示例代碼:

private void op_Timer(TextView textView){
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    String startTime = sdf.format(new Date());
    Log.v(TAG, "startTime:" + startTime);
    Observable.timer(2, TimeUnit.SECONDS)
            .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<Long>() {
        @Override
        public void onNext(Long item) {
            //Timer創建的對象在2秒鐘後發射了一個0
            Log.d(TAG,"Next: " + item);
            String endTime =  sdf.format(new Date());
            textView.setText(startTime+":Timer:"+endTime);
            Log.v(TAG, "endTime:" + endTime);
        }
        @Override
        public void onError(Throwable error) {
            System.err.println("Error: " + error.getMessage());
        }
        @Override
        public void onCompleted() {
            Log.d(TAG,"Sequence complete.");
        }
    });

輸出:

startTime:04:28:12
Next: 0
endTime:04:28:14
Sequence complete.

  到此爲止RxJava中實現的創建類操作符我們就學完了,剛剛開始學習操作符的時候,思路可能有點繞,我們現在姑且不要管什麼子線程和主線程,只需要瞭解操作符API的作用和使用方法,到後面學習RxAndroid的時候在着重學習線程相關的內容。有問題請留言,有幫助請點贊(__)

#源碼下載:
https://github.com/openXu/RxJavaTest

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章