咱們已經看到了如何處理觀察者中的錯誤,然而,到那時,咱們實際上已經超出了 Monad 的範圍。錯誤可能有不少種,並非每個錯誤都值得一路推到頂端。在標準Java中,您能夠在任何級別捕獲異常,並決定是在那裏處理仍是進一步拋出。相似地,在Rx中,您能夠基於錯誤定義行爲,而沒必要終止可觀察到的行爲,並強制觀察者處理全部的問題。ios
在下一個示例中,咱們將把錯誤轉換爲要打印的正常值:git
輸出:github
onErrorResumeNext 容許您用另外一個序列恢復失敗的序列。該錯誤不會出如今所獲得的可觀察到的結果中。數據庫
第一個重載在每種狀況下都使用相同的可觀察到的後續操做。第二個重載容許您根據發生的錯誤決定順序。緩存
輸出:函數
沒有什麼能中止 resumeSequence 的失敗。事實上,若是您想更改錯誤的類型,您能夠當即返回一個可觀察到的錯誤。在標準Java中,組件可能會決定它們不能處理錯誤,而應該從新拋出錯誤。在這種狀況下,一般會在原始錯誤周圍包裝一個新的異常,從而提供額外的上下文。在Rx中也能夠這樣作。spa
如今序列仍然失敗,可是您已經將原來的錯誤封裝在一個新的錯誤中。code
onExceptionResumeNext與onErrorResumeNext只有一個區別:它只捕獲做爲異常的錯誤資源
輸出:字符串
若是錯誤是不肯定的,那麼重試多是有意義的。重試從新訂閱源並再次從星號發出全部信息。
若是錯誤沒有消失,retry()將把咱們鎖定在無限重試的循環中。第二個重載限制重試的次數。若是錯誤持續存在且序列失敗n次,則重試(N)也將失敗。讓咱們看一個例子:
這邊有個輸出是 rx.exceptions.OnErrorNotImplementedException,理解不了 ???
在這裏,咱們已經指定要重試一次。咱們的可觀測值在兩個值後失敗,而後再試一次,再失敗一次。第二次失敗時,容許異常經過。
在這個例子中,咱們作了一些棘手的事情:咱們將訂閱狀態設置爲有狀態,以證實可觀察到的是從源從新啓動的:它第二次產生了不一樣的值。retry不緩存任何元素,好比重播,這樣作也沒有意義。只有在有反作用或可觀察到的是熱的狀況下,重試纔有意義。
一旦發生故障,retry 將從新啓動訂閱。若是咱們須要更多的控制,咱們可使用retryWhen
retryWhen的參數是一個接受可觀察值並返回另外一個值的函數。可觀察到的輸入會發出當遇到時再次出現的全部錯誤。當重試時可觀察到的信號:
若是它以錯誤終止,不重試
若是成功終止,則重試也成功終止。
請注意,可觀察到的信號類型和發出的實際值並不重要。這些值被丟棄,可觀測值僅用於計時。
在下一個示例中,咱們將構造一個重試策略,在重試以前等待100 ms。
輸出:
咱們的源可觀察到發出2個值,並當即失敗。當發生這種狀況時,內部可觀察到的故障將在發出錯誤時重試。咱們延遲發射100毫秒,並將其發送回信號重試。 take(2)
保證咱們的信號可觀測到的將終止後,咱們收到兩個錯誤。
using 操做符用於從須要管理的資源中建立observables。它保證不管什麼時候以何種方式終止訂閱,都將管理您的資源。若是隻使用create,就必須在傳統Java範例中進行管理,並將其注入Rx中。在Rx中,using 是一種更天然的管理資源的方式。
當新的訂閱開始時,ResourceFactory 將租用必要的資源。當再也不須要資源時,將使用disposeAction對其進行處置。不管訂閱以何種方式終止(成功或失敗),都將執行Disposal操做。
在下一個示例中,咱們假設字符串是須要管理的資源。
輸出:
當咱們訂閱值時,將調用資源工廠函數,該函數返回「MyResource」。該字符串用於生成一個可觀察的字符串,它會發出字符串中的全部字符。一旦訂閱結束,資源將被釋放。字符串不須要比垃圾回收器所作的更多的管理工做。資源實際上可能須要這樣的管理,例如數據庫鏈接、打開的文件等
這裏須要注意的是,咱們負責終止可觀察到的內容,就像咱們在使用Create方法時所作的那樣。使用create,終止是一個語義問題。using,而不是終止,首先就會破壞使用它的意義。只有在終止時纔會釋放資源。若是咱們沒有調用o.onCompleted(),那麼序列將被假定仍然是活動的,而且須要它的資源
原文連接:
https://github.com/Froussios/Intro-To-RxJava/blob/master/Part%203%20-%20Taming%20the%20sequence/3.%20Advanced%20error%20handling.md