關於Rxjava for android學習(基礎篇)

一 簡介

RxJava是實現異步操作的庫 那麼在有很多異步成熟實現的基礎上 我們爲什麼還要使用RxJava呢?

    異步操作很關鍵的一點是程序的簡潔性,因爲在調度過程比較複雜的情況下,異步代碼經常會既難寫也難被讀懂。 Android 創造的 AsyncTask eventBus 和Handler ,其實都是爲了讓異步代碼更加簡潔。RxJava 的優勢也是簡潔,但它的簡潔的與衆不同之處在於,隨着程序邏輯變得越來越複雜,它依然能夠保持簡潔

二 原理

  RxJava使用的是擴展的觀察者模式 

  傳統的觀察者模式:註冊觀察者 當被觀察者發生變化的時候(發生事件) 能夠及時的通知觀察者 觀察者做出自己的反應 也就是 被觀察者-->觀察者-->訂閱 /註冊-->事件 一般傳統的觀察者 只有點擊 和觸摸事件 也就是過程事件處理onNext  (也就是 onclick()和onEvent())

  擴展的觀察者模式:在傳統觀察者模式的基礎上 添加了完成事件 和錯誤事件處理(onComplete ()和onError()) RxJava不僅將事件進行獨立的處理  還可以將所有事件堪稱一個隊列 進行統一的管理 。

  規定: 當沒有onNext事件進入隊列的時候 就觸發onComplete ()  

              當事件處理過程中發生異常的時候 就出觸發onError()  同時 事件隊列 不允許事件在進行進出  也就是隊列被終止了

具體實現原理在後面 


三 實現

    RxJava的使用和Builder很像 屬於鏈式編程 介紹幾個之後常見的名詞 
         Observable:被觀察者,也就是消息的發送者
         Observer:  觀察者,消息的接收者
         Subscriber:訂閱者,觀察者的另一種表示
         Scheduler:調度器,進行線程切換

   1.首先 搭建環境 添加Rxjava的依賴庫
          compile 'io.reactivex:rxjava:1.2.1'
          compile 'io.reactivex:rxandroid:1.2.1'

   2.下面我們一起來做一個小demo

      2.1 創建一個觀察者 (一般我們在考慮的時候 先找中介 告訴中介我們需要什麼  具體中介怎麼做事情我們是不管的   )

           方式一:使用Observer 

     // 創建觀察者
Observer<String> observable=new Observer<String>() {
@Override
public void onCompleted() {
// 當被觀察者事件對列正常完成 沒有其他事件進入的時候
Log.d(tag, "onCompleted");

}

@Override
public void onError(Throwable e) {
// 當被觀察者隊列中事件執行過程中 出現錯誤的時候
Log.d(tag, "onError");
}

@Override
public void onNext(String s) {
// 事件的執行 就相當於我們在onClick方法中重寫的事件一樣
Log.d(tag, "Item: " + s);
}
};  

      方式二:使用Subscriber(Observer的子類)

Subscriber<String> subscriber=new Subscriber<String>() {
@Override
public void onCompleted() {
// 當被觀察者事件對列正常完成 沒有其他事件進入的時候
Log.d(tag, "onCompleted");

}

@Override
public void onError(Throwable e) {
// 當被觀察者隊列中事件執行過程中 出現錯誤的時候
Log.d(tag, "onError");
}

@Override
public void onNext(String s) {
// 事件的執行 就相當於我們在onClick方法中重寫的事件一樣
Log.d(tag, "Item: " + s);
}

@Override
public void onStart() {
super.onStart();
}

};
subscriber.unsubscribe();

我們可以看到  對於subscriber 屬於observer的子類(但是一般由observer聲明的訂閱者 也會轉成Subscriber) 相對於父類來說 他添加了onstart方法  該方法在觀察者被調用 但是 onnext()方法還沒有執行前調用  一般在事件沒有發送前 做一些準備工作 比如數據的清零或者重置  該方法並不是抽象方法  但是需要注意的是 該方法一般執行在訂閱所在的線程  並不能制定線程來執行 所以如果是對UI的操作(比如 進度條等操作) 一般不在該方法進行。如果需要指定的線程來做準備工作,可以使用 doOnSubscribe() 方法


兩者的區別:

   Subscriber可以調用unSubscribe()方法 取消訂閱 

2.2 創建被訂閱者(被觀察者)

// 創建被訂閱者 在傳入參數的時候就可以看出來 是將Observer轉化成對應的子類
Observable<String> observable= Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
// 調用訂閱者的方法
subscriber.onStart();
subscriber.onNext("hello world");

subscriber.onNext("hello world111111");
subscriber.onError(new Throwable("失敗了"));
subscriber.onCompleted();
}
});
}

當Observable被訂閱的時候 就會調用call方法  事件會被依次執行

// 訂閱
observable.subscribe(subscriber);

除了上述的create方法 Observable 對象的時候 Rxjava海提供了快速創建的方式

Create — 通過調用觀察者的方法從頭創建一個Observable
Defer — 在觀察者訂閱之前不創建這個Observable,爲每一個觀察者創建一個新的Observable
Empty/Never/Throw — 創建行爲受限的特殊Observable
From — 將其它的對象或數據結構轉換爲Observable
Interval — 創建一個定時發射整數序列的Observable
Just — 將對象或者對象集合轉換爲一個會發射這些對象的Observable
Range — 創建發射指定範圍的整數序列的Observable
Repeat — 創建重複發射特定的數據或數據序列的Observable
Start — 創建發射一個函數的返回值的Observable
Timer — 創建在一個指定的延遲之後發射單個數據的Observable ..


一般根據需要進行選擇


2.3 訂閱

   講了這麼多  還沒有講兩者鏈接起來  者怎麼整呢? 使用訂閱方法 講訂閱者何被訂閱者 連接起來 才能實現他們之間的互動 

  爲了練時編程的方便  將格式定義成了  

 // 訂閱
observable.subscribe(subscriber);  這麼看來 好像反了 被訂閱者訂閱了訂閱者  但是爲了連式編程 的方便  只能定義成這樣  那麼我們就跑跑吧
Observable.subscribe(Subscriber) 的內部實現是這樣的(僅核心代碼):

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

調用 Subscriber.onStart() 。這個方法在前面已經介紹過,是一個可選的準備方法。
調用 Observable 中的 OnSubscribe.call(Subscriber) 。在這裏,事件發送的邏輯開始運行。從這也可以看出,在 RxJava 中,Observable 並不是在創建的時候就立即開始發送事件,而是在它被訂閱的時候,即當 subscribe() 方法執行的時候。
將傳入的 Subscriber 作爲 Subscription 返回。這是爲了方便 unsubscribe().

10-13 16:34:52.043 6025-6025/? D/MainActivity: Item: hello world
10-13 16:34:52.043 6025-6025/? D/MainActivity: onCompleted

ok 

除了完整定義 還有不完整定義

除了 subscribe(Observer) 和 subscribe(Subscriber) ,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);
簡單解釋一下這段代碼中出現的 Action1 和 Action0。 Action0 是 RxJava 的一個接口,它只有一個方法 call(),這個方法是無參無返回值的;由於 onCompleted() 方法也是無參無返回值的,因此 Action0 可以被當成一個包裝對象,將 onCompleted() 的內容打包起來將自己作爲一個參數傳入 subscribe() 以實現不完整定義的回調。這樣其實也可以看做將 onCompleted() 方法作爲參數傳進了subscribe(),相當於其他某些語言中的『閉包』。 Action1 也是一個接口,它同樣只有一個方法 call(T param),這個方法也無返回值,但有一個參數;與 Action0 同理,由於 onNext(T obj) 和 onError(Throwable error) 也是單參數無返回值的,因此 Action1可以將 onNext(obj) 和 onError(error) 打包起來傳入 subscribe() 以實現不完整定義的回調。事實上,雖然 Action0 和 Action1在 API 中使用最廣泛,但 RxJava 是提供了多個 ActionX 形式的接口 (例如 Action2, Action3) 的,它們可以被用以包裝不同的無返回值的方法。


就是使用Action 實現 將方法進行包裝  生成不完整的訂閱者 


說了一大半天  練時編程呢  讓我們連起來 吧

String[] words={"aa","cc","bb"};
// 將數組轉化成被訂閱者對象 然後註冊 訂閱者 使用不完整定義定義訂閱者對象
Observable.from(words).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.d(tag,s);
}
});

跑跑唄 

10-13 16:46:51.213 18046-18046/com.example.rxdemo D/MainActivity: aa
10-13 16:46:51.213 18046-18046/com.example.rxdemo D/MainActivity: cc
10-13 16:46:51.213 18046-18046/com.example.rxdemo D/MainActivity: bb
10-13 16:46:51.233 18046-18046/com.example.rxdemo D/Atlas: Validating map...

這個結果真的是運行出來的 不是我自己瞎編的  然而 並沒有什麼卵用


四   異步的實現(線程控制 Scheduler)
    4.1     在 RxJava 的默認規則中,事件的發出和消費都是在同一個線程的。也就是說,如果只用上面的方法,實現出來的只是一個同步的觀察者模式。觀察者模式本身的目的就是『後臺處理,前臺回調』的異步機制,因此異步對於 RxJava 是至關重要的。而要實現異步,則需要用到 RxJava 的另一個概念: Scheduler 。

Scheduler 我在前面大概提了一下 是調度器  實現線程的切換 總而言之 就是完成線程的控制 就成了 

RxJava的線程原則:

        在不制定線程的情況下 RxJava遵循的是線程不變的原則  也就是 訂閱在那個線程 那麼就在那個線程執行  如果需要切換線程  就需要使用Scheduler 進行線程的切換 

Scheduler的使用:

      RxJava已經內置了幾個常用的Scheduler 能夠解決大部分場景的使用  介紹一下子

Schedulers.immediate(): 直接在當前線程運行,相當於不指定線程。這是默認的 Scheduler。

Schedulers.newThread(): 總是啓用新線程,並在新線程執行操作。
Schedulers.io(): I/O 操作(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler。行爲模式和 newThread() 差不多,區別在於 io() 的內部實現是是用一個無數量上限的線程池,可以重用空閒的線程,因此多數情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中,可以避免創建不必要的線程。
Schedulers.computation(): 計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作,例如圖形的計算。這個 Scheduler 使用的固定的線程池,大小爲 CPU 核數。不要把 I/O 操作放在                                                              computation() 中,否則 I/O 操作的等待時間會浪費 CPU。
另外, Android 還有一個專用的 AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運行。
有了這幾個 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 兩個方法來對線程進行控制了。

subscribeOn(): 指定 subscribe() 所發生的線程,即 Observable.OnSubscribe 被激活時所處的線程。或者叫做事件產生的線程。
observeOn(): 指定 Subscriber 所運行.observeOn(AndroidSchedulers.mainThread()) // 指定事件的回調發生在主線程的線程。或者叫做事件消費的線程。

 /**
* 指定線程運行
*/
private void demo2() {
Observable.just(1,2,3,4) //將整形數據轉化成被訂閱者對象
.subscribeOn(Schedulers.io()) // 註冊線程控制發生在io線程 (使用線程控制 調用io進行輸入輸出)

.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程

.subscribe(new Action1<Integer>() { //創建訂閱者 使用不完整定義(有一個參數 沒有返回值 )
@Override
public void call(Integer integer) {
Log.d("demo2","num="+integer);
}
});
}


結果我就不說了  註釋寫得很清楚

上面這段代碼中,由於 subscribeOn(Schedulers.io()) 的指定,被創建的事件的內容 1、2、3、4 將會在 IO 線程發出;而由於observeOn(AndroidScheculers.mainThread()) 的指定,因此 subscriber 數字的打印將發生在主線程 。事實上,這種在subscribe() 之前寫上兩句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常見,它適用於多數的 『後臺線程取數據,主線程顯示』的程序策略。

不說扯淡的例子了 說個比較實用的例子  我們都知道圖片的加載比較好費時間 有人說了 不是有圖片加載框架嗎 什麼picasso啦 imageLoader了 等等  可以完全ok  自己用着玩吧 但是 底層他們都是需要請求網絡加載圖片的  一般使用的Asynctask進行實現的  那麼我之前也說個 Rxjava最大的用處就是異步  那麼 我們底層完全可以根據Rxjava來實現  來個小例子 

Observable.create(new Observable.OnSubscribe<Drawable>() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void call(Subscriber<? super Drawable> subscriber) {
int drawableRes = R.mipmap.ic_launcher;
Drawable drawable = getTheme().getDrawable(drawableRes);
// 設置加載完成前的默認現實圖片
subscriber.onNext(drawable);
// 模擬加載圖片
SystemClock.sleep(2000);
drawable=getTheme().getDrawable(R.mipmap.icon_baoxiudan_wxdd);
subscriber.onNext(drawable);
// 圖片加載完成後進行圖片的替換
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 線程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程
.subscribe(new Observer<Drawable>() {
@Override
public void onNext(Drawable drawable) {
imageView.setImageDrawable(drawable);
}

@Override
public void onCompleted() {
}

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


結果 我就不說了  要不會顯得太沒檔次

4.2 變換 

--1. map() 將String類型轉化成Bitmap類型的對象然後將對象進行返回  (事務對象直接變換 最常見 也最容易 )

demo:

  Observable.just(new File(Environment.getExternalStorageDirectory(),"Pictures/JPEG_20160803_003209.jpg").getAbsolutePath())
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String path) {
return getBitmapFromPath(path);//根據路徑獲取bitMap圖片 
}
})
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) {
imageView.setImageBitmap(bitmap); //將圖片顯示在指定的控件中 
}
});

關於返回值的問題:

   ActionX 是沒有返回值的java的接口實現類 (Action0 沒有參數 Action1有一個參數 我前面已經說過了  不過我自己又忘記了)

   FunX 是有返回值的java接口實現類  

--2.flatMap()

需求:輸出一個數據中所有學生對應的課程信息 

使用map()實現 

ArrayList<String> course=new ArrayList<String>();
course.add("1");
course.add("2");
course.add("3");
Student student1=new Student(123,"zhang",18,course);
Student student2=new Student(124,"zhang1",19,course);
student=new Student[2];
student[0]=student1;
student[1]=student2;
Observable.from(student)
.map(new Func1<Student, Student>() {
@Override
public Student call(Student student) {
return student;
}
})
.subscribe(new Subscriber<Student>() {
@Override
public void onCompleted() {

}

@Override
public void onError(Throwable e) {

}

@Override
public void onNext(Student s) {
// TODO 遍歷循環輸出對應課程
Log.d(tag,"===="+s);
}
});


遍歷 很麻煩 我們就像 能不能不這麼煩 直接傳遞給我課程信息 然後我們直接就輸出了 遍歷幹嘛 

鄉親們 不要着急  我們使用flatmap()實現一下 

Observable.from(student)
.flatMap(new Func1<Student, Observable<String>>() {
//第一個參數便是傳入的參數類型 第二個參數是想要得到的參數類型 在當前例子中我們需要得到的是各門學科的名稱
@Override
public Observable<String> call(Student student) {
return Observable.from(student.getCourses());
//獲取學科數據 轉化成被訂閱者類型 具體爲什麼能夠直接取出學科中的數據 請看原理
}
})
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {

}

@Override
public void onError(Throwable e) {

}

@Override
public void onNext(String name) {
Log.d(tag,name);

}
});


上面例子使用起來是不是就簡單了 大兄弟 那下面我們看看原理

flatMap() 的原理是這樣的:

 1. 使用傳入的事件對象創建一個 Observable 對象;

 2. 並不發送這個 Observable, 而是將它激活,於是它開始發送事件;

 3. 每一個創建出來的 Observable 發送的事件,都被匯入同一個 Observable ,而這個 Observable 負責將這些事件統一交給 Subscriber 的回調方法。這三個步驟,把事件拆成了兩級,通過一組新創建的 Observable 將初始的對象『鋪平』之後通過統一路徑分發了下去。而這個『鋪平』就是 flatMap() 所謂的 flat。

來點高級的:

   一般可以在flatmap中進行異步操作 所以可以進行網絡請求吧 這就涉及到Retrofit了 我們可以使用retrofit+RxJava來代替ok和EventBus

具體代碼我站在下面了 從別的地方站過來的 因爲我還沒學習Retrofit 尷尬了

  1. networkClient.token() // 返回 Observable<String>,在訂閱時請求 token,並在響應後發送 token
  2.     .flatMap(new Func1<String, Observable<Messages>>() {
  3.         @Override
  4.         public Observable<Messages> call(String token) {
  5.             // 返回 Observable<Messages>,在訂閱時請求消息列表,並在響應後發送請求到的消息列表
  6.             return networkClient.messages();
  7.         }
  8.     })
  9.     .subscribe(new Action1<Messages>() {
  10.         @Override
  11.         public void call(Messages messages) {
  12.             // 處理顯示消息列表
  13.             showMessages(messages);
  14.         }
  15.     });
一般我們在使用ok等網絡請求框架的時候使用callback進行結果的回調 那麼 廣大的鄉親們注意了 我們現在不需要了  我們只需要一條鏈 通過flatMap就可以搞定了 這樣程序會少了幾個接口 世界安靜了 

下面在看一個省事的throttleFirst():

RxView.clicks(imageView)
.throttleFirst(500, TimeUnit.MILLISECONDS)
.subscribe(new Action1<Void>() {
@Override
public void call(Void aVoid) {
Log.d(tag,"間隔0.5s點擊有作用 用來過濾點擊的");
}
});

throttleFirst():是用來過濾事件的 在制定間隔時間內的事件時不給予處理的  常用來做都送處理 媽媽再也不用擔心惡作劇的頻繁點擊了 

對於事件序列的處理還有很多 在後續的文中我在介紹(但願還有後續)


4.3 變換的原理

   在上面的例子中我們都是對事件的序列進行的處理 看似葛優特點 但其實都是對事件序列的管理 也就是重新處理事件 然後在發送 

   在RxJava中他們都是 通過一個共同的方法實現的  lift(操作) 核心代碼(不用說 又是從別的地方拿來的):

  

  1. // 注意:這不是 lift() 的源碼,而是將源碼中與性能、兼容性、擴展性有關的代碼剔除後的核心代碼。
  2. // 如果需要看源碼,可以去 RxJava 的 GitHub 倉庫下載。
  3. public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
  4.     return Observable.create(new OnSubscribe<R>() {
  5.         @Override
  6.         public void call(Subscriber subscriber) {
  7.             Subscriber newSubscriber = operator.call(subscriber);
  8.             newSubscriber.onStart();
  9.             onSubscribe.call(newSubscriber);//這個onSubscribe是新的的Observable的 通知給原來的Observable的Observable
  10.         }
  11.     });
  12. }

   改方法的返回值是Observable 原來我們有一個Observable 但是通過這個方法之後我們就有了兩個Observable  我們成爲 原來的 和新的(能理解吧 不能理解就走吧)

簡單來說:

  在新的Observable中 通過opertor.call方法 將創建新的Subscriber(在opertor中包含着用戶定義的變換 那麼這樣就相當於將新的變化插入到新的Subscriber中了),並且和舊的Subscriber建立聯繫 那麼此時 newSubscriber就可以向原來的observable進行訂閱

注意啦注意啦 父老鄉親們:

    講述 lift() 的原理只是爲了讓你更好地瞭解 RxJava ,從而可以更好地使用它。然而不管你是否理解了 lift() 的原理,RxJava 都不建議開發者自定義 Operator 來直接使用 lift(),而是建議儘量使用已有的 lift() 包裝方法(如map() flatMap() 等)進行組合來實現需求,因爲直接使用 lift() 非常容易發生一些難以發現的錯誤。

4.4 compose (對 observable整體的轉換) 

 都是轉換 那麼 lift 和compose的區別是什麼呢

 lift:對事件序列的改變 

 compose:針對 observable本身的轉換

有的鄉親大哥就說了 貌似沒有什麼卵用

 那麼我們看一個需求 : 如果我們需要對一個observable進行多個轉換 ? 老張頭說:直接使用多個lift() 不久成了  反正每個的返回值都是Observable 多次轉換沒毛病

                                       如果我們需要對多個observable進行多個相同的轉換? 老李頭說:直接封裝方法 往裏面傳observable不久成了   有瑕疵 這樣好像限制了observable的靈                                        活性  那怎麼辦 找小舅子好像不靠譜  那麼這個就需要compose上陣了

來個例子:

  1. public class LiftAllTransformer implements Observable.Transformer<Integer, String> {
  2.     @Override
  3.     public Observable<String> call(Observable<Integer> observable) {
  4.         return observable
  5.             .lift1()
  6.             .lift2()
  7.             .lift3()
  8.             .lift4();
  9.     }
  10. }
  11. ...
  12. Transformer liftAll = new LiftAllTransformer();
  13. observable1.compose(liftAll).subscribe(subscriber1);
  14. observable2.compose(liftAll).subscribe(subscriber2);
  15. observable3.compose(liftAll).subscribe(subscriber3);
  16. observable4.compose(liftAll).subscribe(subscriber4);
又是粘來的  關鍵是代碼太多  明白意思就成了 

5.線程控制scheduler(調度器)二

  在4裏面我們白活了事件序列的變換 什麼map  flatmap 以及他們的基本原理  我們還白活了一下 如何制定線程運行 比如圖片加載等 忘了的鄉親們 回頭瞅瞅去 別乾瞪眼 

 (可以利用 subscribeOn() 結合 observeOn() 來實現線程控制,讓事件的產生和消費發生在不同的線程) 結合之前的map()和 flatmap()我們瞭解了原理 那我們就像能不能產生多次線程的變換呢

  observableOn()指定的是subscriber(訂閱者)的線程 那麼當然這個訂閱者 不一定是subscribe()方法調用的註冊者 (通過之前我們講述 lift原理可知 ) 所以observeOn()執行的subscriber並不是Observable所對應的subscriber 而是他的下一級 或者說是我們上面說的新的subscriber  那麼我們就可以這樣說 : 如果需要切換線程 那麼我們只需要調用observeOn()就可以啦


subscribeOn() 和 observeOn() 都做了線程切換的工作。不同的是, subscribeOn()的線程切換髮生在 OnSubscribe 中,即在它通知上一級 OnSubscribe 時,這時事件還沒有開始發送,因此 subscribeOn() 的線程控制可以從事件發出的開端就造成影響;而 observeOn() 的線程切換則發生在它內建的 Subscriber 中,即發生在它即將給下一級Subscriber 發送事件時,因此 observeOn() 控制的是它後面的線程。

5.1擴展 

最近項目太忙了 未完待續...









 







      






 


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