rxjava

Rxjava到底是什么

一個詞:異步
一個可以在java VM上使用可觀測的序列來組成異步的、基本事件的程序庫
一個實現異步操作的庫

RXJava優缺點

簡潔
隨著程序的邏輯變得越來越復雜,它依然能夠保持簡潔。

API介紹和原理解析

1.概念:擴展的觀察者模式

RXjava的異步實現,是通過一種擴展的觀察者模式

觀察者模式

觀察者模式的面向需求是:對象A(觀察者)對對象B(被觀察者)的某種變化,高度敏感,需要在B變化的一瞬間做出反應。
觀察者模式采用注冊(register)或者成為訂閱(subscrible)的方式,告訴被觀察者,我需要你的某某狀態,你要在它變化的時候告訴我。
Android開發中典型的例子就是view的點擊監聽器OnClickLinstener()。對設置onClickListener來說,view是被觀察者,OnClickListener是觀察者,二者通過setOnClickListener完成訂閱關系。訂閱完成之后,用戶點擊view的瞬間,Android Framework就會將點擊事件交給已經注冊的onClickListener采取這樣被動的觀察方式,既省去了反復檢索狀態的資源消耗,也能夠得到最高的反饋速度。

OnClickListener 的模式大致如下圖:

[圖片上傳失敗...(image-2917dc-1512961567324)]

如圖所示,通過setOnClickListener方法Button持有OnClickListener的引用,當用戶點擊Button,自動調用OnclickListener里的onClick方法。
把圖片抽象出來 Button->被觀察者 OnClickListener->觀察者 setOnClickListener->訂閱 onClick->事件。就由專用的觀察者模式(例如只用于監聽控件點擊)轉變成了通用的觀察者模式。

[圖片上傳失敗...(image-ed19bb-1512961567324)]

而 RxJava 作為一個工具庫,使用的就是通用形式的觀察者模式。

RXJava的觀察者模式

RXjava有4個感念:

  • Observable 被觀察者
  • Observer 觀察者
  • subscribe 訂閱
  • 事件

Observable和Observer通過Subscribe方法實現訂閱,從而Observable可以在需要的時候發出事件通知Observer。

與傳統的觀察者模式不同,除了普通事件onNext() (相當于onClick/OnEvent),還定義兩個特殊的事件onCompleted(),onError | completed 完成 完整的|

  • onComplete() 事件隊列完結。RXJava不僅把每個事件單獨處理,還會把他們看成一個隊列RXJava規定,如果沒有新的onNext()方法發出時,必須出發onCompleted方法作為完成標志。
  • onError() 事件隊列異常,在事件處理過程中出現異常,會觸發onError(),并且整個事件終止,不允許在有事件發出。
  • 在一個正確運行事件序列中,onCompleted,onError有且只有一個會被調用,而且是事件中最后一個方法,兩個方法是互斥的。即在隊列中調用了其中一個,就不應該再調用另一個。

RxJava 的觀察者模式大致如下圖:

[圖片上傳失敗...(image-f381dc-1512961567324)]

基本實現

基于以上的概念, RxJava 的基本實現主要有三點:

創建Observer 觀察者

決定著事件觸發將有怎樣的行為

 Observer<String> observer = new Observer<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

除了 Observer 接口之外,RxJava 還內置了一個實現了 Observer 的抽象類:Subscriber。 Subscriber 對 Observer 接口進行了一些擴展,但他們的基本使用方式是完全一樣的:

Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

不僅基本使用方式一樣,實質上,在RxJava的subscribe過程中,Observer也總是會先被轉換成Subscriber在使用。所以使用基本功能,選擇Observer或者subscriber都是一樣的。他們的區別有兩點。

  1. onStart() 這是subscriber新增方法,他會在subscribe剛開始,但是事件還沒有發送之前被調用,可以用于做一些準備工作,例如數據清零或者重置,這是一個可選的方法。默認實現為空。但是如果對工作線程有要求的話(例如彈出一個對話框,需要在Ui線程執行),就不能使用onStart(),因為他總是調用在subscribe所發生的線程調用,而不能指定線程。如果指定線程來做準備工作,可以使用doOnSubscribe()方法。
  2. unSubscribe 這是Subscriber所實現的另一個接口Subscription()方法,用于取消訂閱,在這個方法調用后Subscriber將不接受任何事件。一般在調用之前先使用isUnSubscribed先判斷一下狀態,unSubscribe()這個方法很重要,因為在subscribe之后,Observable會持有Subscriber的引用,這個引用如果不能及時被釋放,將有內存泄露的風險。所以要保持良好的原則,要在不再使用的時候盡快在合適的地方(例如 onPause() onStop() 等方法中)調用 unsubscribe() 來解除引用關系,以避免內存泄露的發生。

創建Observeable

Observable是被觀察者,決定在什么時候被觸發,和觸發什么事件。
RXJava使用create()方法來創建一個Observable,并為他設置事件觸發規則。

Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("Hi");
        subscriber.onNext("Aloha");
        subscriber.onCompleted();
    }
});

這里傳入OnSubScribe對象作為參數,OnSubscribe會被存入染回的Observable對象中,相當于一個計劃表,當OnSubscribeObservable被訂閱時,OnSubscriable的call方法會被自動調用,事件序列會按照設定依次調用onNext方法和OnCompleted方法,這樣,由被觀察者調用了觀察者的回調方法,就實現了被觀察者向觀察者的事件傳遞,即觀察者模式

create方法是RXJava中最基本的創造事件序列的方法。RXJava還提供了一些方法用來快捷創建事件隊列,例如:

  • just<T...> 將傳入的參數依次發送出來。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 將會依次調用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
  • from(T...) / from(Iterable<? extends T> 將傳入的數組 或者 Iterable 拆分成具體對象后,依次發送出來。
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
// 將會依次調用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();

上面 just(T...) 的例子和 from(T[]) 的例子,都和之前的 create(OnSubscribe) 的例子是等價的。

Subcsribe訂閱

創建了Observable和Observe之后,用subscribe方法將他們鏈接起來,整條鏈子就可以工作了。

observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);

Observable.subscribe(Subscriber) 的內部實現是這樣的(僅核心代碼):

// 注意:這不是 subscribe() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除后的核心代碼。
// 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);
    return subscriber;
}

subscribe做了三件事

  1. 調用的Subscriber的onStart方法,可選的準備方法。
  2. 調用observable中的Call方法。在這里,事件發送的邏輯開始運行。在RXjava中Observable不是在創建時候就立即發送事件,而是在他訂閱的時候,即放subscribe執行的時候。
  3. 將傳入的subscribe作為Subscription返回,為了方便unSubscribe。

整個關系如下

[圖片上傳失敗...(image-17e6e0-1512961567324

或者

[圖片上傳失敗...(image-7845b8-1512961567324)]

除了subscribe(Observer) 或者 subscribe(subscriable),subscribe還支持不完整定義的回調,RXJava會自動創建出Subscriber

Action1<String> onNextAction = new Action1<String>() {
    // onNext()
    @Override
    public void call(String s) {
        Log.d(tag, s);
    }
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
    // onError()
    @Override
    public void call(Throwable throwable) {
        // Error handling
    }
};
Action0 onCompletedAction = new Action0() {
    // onCompleted()
    @Override
    public void call() {
        Log.d(tag, "completed");
    }
};

// 自動創建 Subscriber ,并使用 onNextAction 來定義 onNext()
observable.subscribe(onNextAction);
// 自動創建 Subscriber ,并使用 onNextAction 和 onErrorAction 來定義 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自動創建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 來定義 onNext()、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

Action0是RxJava中的一個接口,它只有一個方法Call,這個方法是一個無參無返回值的方法,由于onCompleted也是無參無返回值的,因此action可以當成一個包裝對象,將onCompleted內容打包起來將自己作為一個參數傳入subscribe中,以實現不完整定義的回調。也可以看做將onCompleted方法傳遞進了subscribe,相當于某些語言中的閉包。

Action1也是一個接口,他同樣也只有一個方法Call(T param),這個方法無返回值,但是有一個參數,與Action0同理,由于onNext onError也是只有一個單參數,且沒有返回值,因此Action1可以將OnNext(obj)和onError(error)打包起來傳入subscribe中,以實現不完整定義的回調,事實上,雖然 Action0 和 Action1 在 API 中使用最廣泛,但 RxJava 是提供了多個 ActionX 形式的接口 (例如 Action2, Action3) 的,它們可以被用以包裝不同的無返回值的方法。

場景事例

打印字符數組

將字符串數組 names 中的所有字符串依次打印出來:

 String[] names = {"馮星","曹操","趙云","馬超"};
        rx.Observable.from(names).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                Log.d(TAG, "call: " +s);
            }
        });

由 id 取得圖片并顯示

由指定的一個 drawable 文件 id drawableRes 取得圖片,并顯示在 ImageView 中,并在出現異常的時候打印 Toast 報錯:

Observable<Drawable> observable = Observable.create(new Observable.OnSubscribe<Drawable>() {
            @Override
            public void call(Subscriber<? super Drawable> subscriber) {
                subscriber.onNext(getResources().getDrawable(R.mipmap.water));
                subscriber.onCompleted();
            }
        });
        observable.subscribe(new Subscriber<Drawable>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                Toast.makeText(MainActivity.this,e.getMessage(),Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onNext(Drawable drawable) {
                iv_demo.setImageDrawable(drawable);
            }
        });

正如上面兩個例子這樣,創建出 Observable 和 Subscriber ,再用 subscribe() 將它們串起來,一次 RxJava 的基本使用就完成了。非常簡單。

[圖片上傳失敗...(image-9074f5-1512961567324)]

在RXjava默認規則里,事件的發出和消費都在同一個線程里。也就是說上面是一個同步的觀察者模式。

而觀察者模式本身的目的在于 后臺處理,前臺調用 的異步機制。因此異步對于 RxJava 是至關重要的。而要實現異步,則需要用到 RxJava 的另一個概念: Scheduler 。

線程控制 -- Scheduler |si gan diu le| 調度

在不指定線程的情況下,RXjava遵循的是線程不變得原則,

即,在那個線程調用Subscribe,就在哪個線程生產事件;在哪個線程生產的事件,就在那個線程消費事件,

如果需要切換線程,就需要用到 Scheduler (調度器)。

Schedule的API

在RXjava中,schedule--調度器,相當于線程控制器,RXJava通過它來指定每一段代碼應該運行哪一個線程。

  • Schedulers.immediate() 運行在當前線程,相當于不指定線程。這是默認的schedule。 |ai mi dei rui te| 立即的 立刻的
  • Schedulers.newThread() 總是啟用新線程。并在新線程執行操作。
  • Schedulers.io() io操作(讀寫文件,讀寫數據庫,網絡信息交互等)所使用的schedule。行為模式和newThread差不多。區別在于Io的內部實現是用一個無數量上線的線程池,可以重復利用閑置的線程。因此多數情況下,io要比newThread更有效。不要把計算工作放在 io() 中,可以避免創建不必要的線程。
  • Schedulers.computation() 計算時使用的schedule。這個計算指的是CPU密集型計算,即不會被I/O等操作限制性能的操作,例如圖形計算。這個Scheduler使用固定的線程池,大小為CPU的核數,不要把I/O放在computation中,否則I/O操作的等待時間會浪費CPU
  • AndroidSchedules.mainThread() Android專用線程,他指定的操作將在主線程中運行。

subscribeOn() 指定subscribe()所發生的線程,即Observable.OnSubscribe()被激活時所發生的線程?;蛘呓凶鍪录a生的線程。

ObserveOn()指定subscriber所發生的線程或者叫做事件消費的線程。

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 線程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

由于subscribeOn(Schedulers.io())的指定,被創建的事件1,2,3,4,將會在在Io線程發出。
由于observeOn(AndroidSchedulers.mainThread())的指定,因此subscriber的數字打印將發生在主線程。

事實上,這種在 subscribe() 之前寫上兩句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常見,它適用于多數的 『后臺線程取數據,主線程顯示』的程序策略。

Schedule的原理

下面呢

變換

RxJava 提供了對事件序列進行變換的支持,這是它的核心功能之一

所謂變換,就是將事件序列中的對象或者整個序列進行加工處理,轉換成不同的事件或者事件序列。

API

map()

Observable.just(R.mipmap.water)
                .map(new Func1<Integer, Bitmap>() {
                    @Override
                    public Bitmap call(Integer s) {
                        return BitmapFactory.decodeResource(getResources(),s);
                    }
                })
                .observeOn(Schedulers.io())
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Bitmap>() {
                    @Override
                    public void call(Bitmap bitmap) {
                        iv_demo.setImageBitmap(bitmap);
                    }
                });

Func1和Action1非常相似。也是RXJava中的一個接口。用于包裝有一個參數的方法。Func1和Action1的區別在于,Func1是由返回值得。另外,和 ActionX 一樣, FuncX 也有多個,用于不同參數個數的方法。FuncX 和 ActionX 的區別在 FuncX 包裝的是有返回值的方法。

map()方法將參數中的string對象轉換成BitMap對象后返回,經過map方法后,事件的參數也隨之變成的bitmap

  • map():事件對象的直接變換,是最常見的轉換。

[圖片上傳失敗...(image-2a65d2-1512961567324)]

  • flatMap() 這是一個很有用但非常難理解的變換,因此我決定花多些篇幅來介紹它。 首先假設這么一種需求:假設有一個數據結構『學生』,現在需要打印出一組學生的名字。實現方式很簡單:
Observable.from(students)
                .map(new Func1<Student, String>() {
                    @Override
                    public String call(Student student) {
                        return student.getName();
                    }
                })
                .observeOn(Schedulers.io())
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.d(TAG, "call: "+s);
                    }
                });

很簡單。那么再假設:如果要打印出每個學生所需要修的所有課程的名稱呢?(需求的區別在于,每個學生只有一個名字,但卻有多個課程。)首先可以這樣實現:

 Observable.from(students)
                .subscribe(new Action1<Student>() {
                    @Override
                    public void call(Student student) {
                        List<Course> courses = student.getCourses();
                        for(Course course : courses){
                            Log.d(TAG, "onNext: "+ course.getName() + "    Student : " +student.getName());
                        }
                    }
                });

依然很簡單。那么如果我不想在 Subscriber 中使用 for 循環,而是希望 Subscriber 中直接傳入單個的 Course 對象呢(這對于代碼復用很重要)?用 map() 顯然是不行的,因為 map() 是一對一的轉化,而我現在的要求是一對多的轉化。那怎么才能把一個 Student 轉化成多個 Course 呢? 這時候就需要flatMap了

Observable.from(students)
                .flatMap(new Func1<Student, Observable<Course>>() {
                    @Override
                    public Observable<Course> call(Student student) {
                        return Observable.from(student.getCourses());
                    }
                }).subscribe(new Action1<Course>() {
            @Override
            public void call(Course course) {
                Log.d(TAG, "call: " + course.getName());
            }
        });

flatMap和map有個相同點:也是把傳入的參數轉化之后返回另一個對象。但是需要注意的是flatMap返回的對象是Observable對象。并且這個Observable對象不是直接發送到了Subscriber的回調方法中。

flatMap的原理是這樣的

  1. 使用傳入的事件對象創建一個Observable對象。
  2. 并不發送這個Observable對象,而是將它激活,于是它開始發送事件。
  3. 每一個創建出來的Observable發送的事件,都匯入同一個Observable對象,而這個observable對象負責將這些事件傳入Subscriber對象。

這三個步驟吧事件分成了兩級,通過一組新創建的Observable將初始的對象鋪平,之后通過統一路徑分發下去,而這個『鋪平』就是 flatMap() 所謂的 flat

flatMap()示意圖

[圖片上傳失敗...(image-a79136-1512961567324)]

擴展

由于可以在嵌套的 Observable 中添加異步代碼, flatMap() 也常用于嵌套的異步操作,例如嵌套的網絡請求。示例代碼(Retrofit + RxJava):

networkClient.token() // 返回 Observable<String>,在訂閱時請求 token,并在響應后發送 token
    .flatMap(new Func1<String, Observable<Messages>>() {
        @Override
        public Observable<Messages> call(String token) {
            // 返回 Observable<Messages>,在訂閱時請求消息列表,并在響應后發送請求到的消息列表
            return networkClient.messages();
        }
    })
    .subscribe(new Action1<Messages>() {
        @Override
        public void call(Messages messages) {
            // 處理顯示消息列表
            showMessages(messages);
        }
    });

傳統的嵌套請求需要使用嵌套的 Callback 來實現。而通過 flatMap() ,可以把嵌套的請求寫在一條鏈中,從而保持程序邏輯的清晰。

  • throttleFirst(): 在每次事件觸發后的一定時間間隔內丟棄新的事件。常用作去抖動過濾,例如按鈕的點擊監聽器: RxView.clickEvents(button) // RxBinding 代碼,后面的文章有解釋 .throttleFirst(500, TimeUnit.MILLISECONDS) // 設置防抖間隔為 500ms .subscribe(subscriber); 媽媽再也不怕我的用戶手抖點開兩個重復的界面啦。 |si rou te| 喉嚨 壓制 節流 減速 窒息

變換的原理 lift()

這些變化雖然功能不一樣,但實質上都是針對事件的處理在發送。而在RXjava的內部,他們都是基于同一個基礎的方法變化,lift(Operator)。

// 注意:這不是 lift() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除后的核心代碼。
// 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
    return Observable.create(new OnSubscribe<R>() {
        @Override
        public void call(Subscriber subscriber) {
            Subscriber newSubscriber = operator.call(subscriber);
            newSubscriber.onStart();
            onSubscribe.call(newSubscriber); // 這個onSubscribe是原始的OnSubScribe對象??!
        }
    });
}

這段代碼,它生成了一個新的Observable并且返回,新創建的Observable中的參數OnSubscribe的回調方法call()的實現,和Observable.Subscribe()基本一樣,但是是由區別的。

不一樣的地方在與OnSubscrvable中call(subscribe)所指代了對象不同

  • 當使用lift方法時,
  1. 假設有一個Observable<T>調用了lift()并創建Observable后,一共有個Observable。
  2. 同樣的Observable的參數OnSubscribe,加上之前原始的Observable里面的原始OnSubscribe,也就有了兩個 OnSubscribe;
  3. 然后調用Observable.create傳入Observable<R>,觸發onSubscribe的Call方法,也是就override的方法,
  4. 在該方法中 調用了OnSubscribe.call()方法,注意:這個OnSubscribe方法是原始的Observable<T>的onSubscribe<T>對象。他需要傳入一個Subscriber對象,這個對象是通過Subscriber newSubscriber = operator.call(subscriber);operator.call()方法生成的新的Subscribe。正是這個operator對象將兩個Subscriber對象聯系起來的。OnSubscribe<T>在執行Subscriber<R>.onNext(R r),而這里從T變成R,正好用到了傳到Operator中的參數Func1<T, R>。

這樣就實現了 lift() 過程,有點像一種代理機制,通過事件攔截和處理實現事件序列的變換。

也可以這個說:在Observable執行了lift(Operator)方法后,會返回一個新的Observable,這個新的Observable會象一個代理一樣,負責接受原始的Observable發出的事件,并在處理后發送給Subscriber

[圖片上傳失敗...(image-8fc12c-1512961567324)]

[圖片上傳失敗...(image-925ff1-1512961567324)]

多次調用

[圖片上傳失敗...(image-eb30f8-151296156732

舉個例子

Observable.just(1.34f, 8.3453f, -534.34f, 392.99f)
        .map(new Func1<Float, Integer>() {
            @Override
            public Integer call(Float aFloat) {
                return Math.round(aFloat);
            }
        })
        .map(new Func1<Integer, String>() {
            @Override
            public String call(Integer integer) {
                return Integer.toBinaryString(integer);
            }
        })
        .subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                log("2 map onNext->" + s);
            }
        });

// outputs
// 2 map onNext->1
// 2 map onNext->1000
// 2 map onNext->11111111111111111111110111101010
// 2 map onNext->110001001

該例子是一個Float->Integer->String的轉換。我們按上面的流程來分析。

  1. 生成一個Observable<Float>
  2. 調用map生成Observable<Integer>
  3. 調用map生成Observable<String>
  4. subscribe()傳入一個Subscribe(String),至此流的前半部分全部完成。
  5. 執行開始,Subscribe<String>發送事件,先生成一個Subscrver<Integer>傳給Observable<Integer>(Observable<Integer>.onSubscribe.call())。
  6. Observable<Interger>開始發送事件,同樣生成一個Subscriber<Float>傳給Observable<Float>(Observable<Float>.onSubscribe.call())。
  7. 真正的發送事件開始,Observable<Float>調用Subscriber<Float>.onNext(Float)等方法,同時Subscriber<Integer>.onNext(Integer)被調用,同時Subscriber<String>.onNext(String)被調用,事件發送完成。

compose對Observable整體的變換 |com pou si| 構成 組成

除了lift方法外,Observable還有一個變換方法叫 compose(Transformer)它和lift的區別在于lift是針對事件項和事件序列,而compose是針對observable自身進行變換。

假設在程序中有多個 Observable ,并且他們都需要應用一組相同的 lift() 變換。

public class LiftAllTransformer implements Observable.Transformer<Integer, String> {
    @Override
    public Observable<String> call(Observable<Integer> observable) {
        return observable
            .lift1()
            .lift2()
            .lift3()
            .lift4();
    }
}
...
Transformer liftAll = new LiftAllTransformer();
observable1.compose(liftAll).subscribe(subscriber1);
observable2.compose(liftAll).subscribe(subscriber2);
observable3.compose(liftAll).subscribe(subscriber3);
observable4.compose(liftAll).subscribe(subscriber4);

像上面這樣,使用 compose() 方法,Observable 可以利用傳入的 Transformer 對象的 call 方法直接對自身進行處理,也就不必被包在方法的里面了。

Scheduler的API(二)

利用 subscribeOn() 結合 observeOn() 來實現線程控制,讓事件的產生和消費發生在不同的線程。

能不能可以多次切換線程
答案是能。因為ObserveOn指定的是

操作符分類

面我按類別把常用操作符分別介紹,其實很多內容都是來自于ReactiveX的官方網站,英文比較好的朋友可以參考(http://reactivex.io/)。
按照官方的分類,操作符大致分為以下幾種:

Creating Observables(Observable的創建操作符),比如:Observable.create()、Observable.just()、Observable.from()等等;
Transforming Observables(Observable的轉換操作符),比如:observable.map()、observable.flatMap()、observable.buffer()等等;
Filtering Observables(Observable的過濾操作符),比如:observable.filter()、observable.sample()、observable.take()等等;
Combining Observables(Observable的組合操作符),比如:observable.join()、observable.merge()、observable.combineLatest()等等;
Error Handling Operators(Observable的錯誤處理操作符),比如:observable.onErrorResumeNext()、observable.retry()等等;
Observable Utility Operators(Observable的功能性操作符),比如:observable.subscribeOn()、observable.observeOn()、observable.delay()等等;
Conditional and Boolean Operators(Observable的條件操作符),比如:observable.amb()、observable.contains()、observable.skipUntil()等等;
Mathematical and Aggregate Operators(Observable數學運算及聚合操作符),比如:observable.count()、observable.reduce()、observable.concat()等等;
其他如observable.toList()、observable.connect()、observable.publish()等等;

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容

  • 我從去年開始使用 RxJava ,到現在一年多了。今年加入了 Flipboard 后,看到 Flipboard 的...
    Jason_andy閱讀 5,546評論 7 62
  • 前言我從去年開始使用 RxJava ,到現在一年多了。今年加入了 Flipboard 后,看到 Flipboard...
    占導zqq閱讀 9,172評論 6 151
  • 最近項目里面有用到Rxjava框架,感覺很強大的巨作,所以在網上搜了很多相關文章,發現一片文章很不錯,今天把這篇文...
    Scus閱讀 6,887評論 2 50
  • 今天算是近來最忙的一天,這種忙來自于平時的懶散積累導致的,大概鋝了一下,對于這半年來做了如下的總結: 禮拜與禱告不...
    尙熏閱讀 519評論 0 0
  • 這個老師,英國人。上面寫的。看他那邊寫著年齡48,他問我幾歲了,估計在上面學習的都是學生,我跟他說很老了,三十多了...
    不曉得rita閱讀 140評論 0 0