理解 RxJava 中的 Single 和 Completable
在大多數 RxJava 示例程式碼和教程中出現最為頻繁的一個類 —— Observable
,它是產生響應式程式設計魔力的關鍵。它的用法很簡單,只需要跟蹤 3 個事件 —— onNext
,onError
和onCompleted
就可以應用上百個操作符來實現自己的表示式。那麼為什麼你還需要了解其他東西?
但是你仔細思考下,你真的需要每次都知道這 3 個事件嗎?實際上,在大多數情況下並不需要。ReactiveX 文件中講述的基本都是關於連續的事件流,因此我們經常忘記通常我們關心的只是監聽單一事件或者只監聽 completed or failed 事件。
在這種情況下我們應該考慮用 RxJava 的兩個絕妙的設計 —— Single<T>
和 Completable
,在分析兩者之前,讓我們先看看他們應用場景的示例。
本文中所有程式碼都是基於 RxJava 2.x ,不是 1.x 版本。如果你還沒升級 RxJava 到最新的 2.x 版本, 強烈建議你馬上升級。
Single
在 Android 中使用 RxJava 最常見的場景就是網路請求,你可能使用 Retrofit 作為專案的 Http client。假設你有一個 GET HTTP 請求返回一些資料,同時使用 RxJavaAdapter 你大概會這麼寫:
public interface APIClient { @GET("my/api/path") Observable<MyData> getMyData(); }
上面的程式碼沒什麼問題,當呼叫它時:
apiClient.getMyData() .subscribe(new Consumer<MyData myData>() { @Override public void accept(MyData myData) throws Exception { // handle data fetched successfully } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception{ // handle error event } }, new Action() { @Override public void run() throws Exception { // handle on complete event } });
仔細思考下,其實這個網路請求並不是一個連續事件流,你只會發起一次 Get 請求返回資料並且只收到一個事件。我們都知道這種情況下 onComplete 會緊跟著 onNext 被呼叫,那為什麼不把它們合二為一呢?
在上面這種情況下為了更清楚的體現請求的意圖,應該用Single<MyData>
替換 Observable。從官方文件中對 Single 的說明可以發現為什麼它是最恰當的選擇:A Single is something like an Observable, but instead of emitting a series of values — anywhere from none at all to an infinite number — it always either emits one value or an error notification。所以修改後 API client 是這樣的:
public interface APIClient { @GET("my/api/path") Single<MyData> getMyData(); }
同時請求的呼叫也可以簡化:
apiClient.getMyData() .subscribe(new Consumer<MyData>() { @Override public void accept(MyData myData) throws Exception { // handle data fetched successfully and API call completed } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception{ // handle error event } });
最值得高興的是 Single 基本上實現了 Observable 所有的操作符 —— map
、flatMap
、filter
、zip
等,如果你發現需要用到一個 Observable 的操作符而 Single 並不支援,你可以用toObservable
操作符把Single<T>
轉換為Observable<T>
。
apiClient.getMyData() .toObservable() // This is an Observable<MyData> now
如果你有 Observable 表現地像 Single 一樣,也可以通過singleOrError
操作符轉換為 Single。
Completable
繼續討論 Retrofit 的例子,再看看另外一種常用場景 —— 通過 PUT 請求更新資料。我們修改了 MyData 型別物件的一些屬性,把它傳送到伺服器更新伺服器資料庫。大部分伺服器 API 設計都是成功後返回更新後的物件,所以你的 API client 的實現是:
public interface APIClient { @PUT("my/api/updatepath") Observable<MyData> updateMyData(@Body MyData data); }
同樣的,跟之前的例子類似,應該這樣呼叫:
apiClient.updateMyData(myUpdatedData) .subscribe(new Consumer<MyData myData>() { @Override public void accept(MyData myData) throws Exception { // handle data fetched successfully and API call completed } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception{ // handle error event } }, new Action() { @Override public void run() throws Exception { // handle completion - what we actually care about } });
你可能會說這裡我們可以同樣用 Single 來簡化程式碼,是的沒錯。在這種情況下我們仍然需要 MyData 結果,確定?伺服器返回給我們更新後的資料是良好的設計,當時實際上僅僅是返回給我們之前傳送給它的物件。我們真正需要的只是更新成功了,這意味著,我只關心 onComplete 事件。
這也是引入Completable
的原因,官方文件對它的描述是:Represents a computation without any value but only indication for completion or exception。使用 Completable 時我們忽略 onNext 事件,只處理 onComplete 和 onError 事件,API client 改寫為:
public interface APIClient { @PUT("my/api/updatepath") Completable updateMyData(@Body MyData data); }
呼叫為:
apiClient.updateMyData(myUpdatedData) .subscribe(new Action() { @Override public void run() throws Exception { // handle completion } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception{ // handle error } });
Completable 本質上來說和 Observable 與 Single 不一樣,因為它不發射資料。因此 Completable 的操作符也有所區別,最常用的是andThen
。在這個操作符中你可以傳任何Observable
、Single
、Flowable
、Maybe
或者其他Completable
,它們會在原來的 Completable 結束後執行。例如。你想執行一些其他操作(Single):
apiClient.updateMyData(myUpdatedData) .andThen(performOtherOperation()) // a Single<OtherResult> .subscribe(new Consumer<OtherResult>() { @Override public void accept(OtherResult result) throws Exception { // handle otherResult } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception{ // handle error } });
跟 Single 不同的是 RxJava 不允許直接把 Observable 轉換為 Completable,因為沒辦法知道一個 Observable 什麼時候 complete。但是你可以把 Single 轉換為 Completable,因為 Single 保證 onComplete 會被呼叫,這個操作符是toCompletable
。
希望通過這篇簡短的對 Single 和 Completable 的介紹能讓你理解這兩個概念從而寫出更簡潔的程式碼。
相關文章
- RxJava的Single、Completable以及MaybeRxJava
- 深入理解RxJava中的觀察者模式RxJava模式
- Rxjava深入理解之自己動手編寫RxjavaRxJava
- RxJava2 中 doFinally 和 doAfterTerminRxJava
- javascript 中{}和[] 的理解JavaScript
- 理解 RxJava 執行緒模型RxJava執行緒模型
- 深入理解 RxJava 的執行緒模型RxJava執行緒模型
- 大話RxJava:三、RxJava的中級使用方法RxJava
- 深入理解 RxJava2:Scheduler(2)RxJava
- 讀RxJava原始碼:理解subscribe原理RxJava原始碼
- RxJava 中的多執行緒RxJava執行緒
- mysqldump的single-transaction和master-dataMySqlAST
- 如何形象地描述 RxJava 中的背壓和流控機制?RxJava
- 深入理解 RxJava2:前世今生(1)RxJava
- 三、Quartz中Scheduler的理解和使用quartz
- iOS中copy和strong的個人理解iOS
- javascript中的prototype和__proto__的理解JavaScript
- 【譯】RxJava 中的錯誤處理RxJava
- 如何理解Spring中的IOC和AOPSpring
- 深入理解Swift中的Class和StructSwiftStruct
- Objective-C中的self和super理解Object
- 理解JavaScript中BOM和DOM的關係JavaScript
- Python中__init__的用法和理解Python
- 深入理解JavaScript中的WeakMap和WeakSetJavaScript
- 理解和使用SQL Server中的並行SQLServer並行
- 對javascript中的call()和apply()的理解JavaScriptAPP
- 深入理解 RxJava2:揭祕 subscribeOn(3)RxJava
- Python 中的引用和類屬性的理解Python
- jquery中dom元素的attr和prop方法的理解jQuery
- 深入理解python中的類和物件Python物件
- 理解Nginx中Server和Location的匹配邏輯NginxServer
- 關於Vue中插槽的理解和總結Vue
- Qt中對js和HTML通訊的理解QTJSHTML
- java學習中對類和物件的理解Java物件
- 理解JavaScript中的作用域和上下文JavaScript
- Python中關於++和—(自增和自減)的理解Python
- 徹底搞懂 RxJava — 中級篇RxJava
- RxJava 和 RxAndroid 二(操作符的使用)RxJavaAndroid