私が理解しているように、RxJava2 values.take(1)
は、元のObservableの要素を1つだけ含む別のObservableを作成します。どのMUST NOTは、2番目に発生したtake(1)
の効果によって除外されるため、例外をスローします。
followingコードスニペットのように
Observable<Integer> values = Observable.create(o -> {
o.onNext(1);
o.onError(new Exception("Oops"));
});
values.take(1)
.subscribe(
System.out::println,
e -> System.out.println("Error: " + e.getMessage()),
() -> System.out.println("Completed")
);
1
Completed
io.reactivex.exceptions.UndeliverableException: Java.lang.Exception: Oops
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.Java:366)
at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onError(ObservableCreate.Java:83)
at ch02.lambda$main$0(ch02.Java:28)
at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.Java:40)
at io.reactivex.Observable.subscribe(Observable.Java:10841)
at io.reactivex.internal.operators.observable.ObservableTake.subscribeActual(ObservableTake.Java:30)
at io.reactivex.Observable.subscribe(Observable.Java:10841)
at io.reactivex.Observable.subscribe(Observable.Java:10827)
at io.reactivex.Observable.subscribe(Observable.Java:10787)
at ch02.main(ch02.Java:32)
Caused by: Java.lang.Exception: Oops
... 8 more
Exception in thread "main" io.reactivex.exceptions.UndeliverableException: Java.lang.Exception: Oops
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.Java:366)
at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onError(ObservableCreate.Java:83)
at ch02.lambda$main$0(ch02.Java:28)
at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.Java:40)
at io.reactivex.Observable.subscribe(Observable.Java:10841)
at io.reactivex.internal.operators.observable.ObservableTake.subscribeActual(ObservableTake.Java:30)
at io.reactivex.Observable.subscribe(Observable.Java:10841)
at io.reactivex.Observable.subscribe(Observable.Java:10827)
at io.reactivex.Observable.subscribe(Observable.Java:10787)
at ch02.main(ch02.Java:32)
Caused by: Java.lang.Exception: Oops
... 8 more
create(...)
内で実行されているコードが停止することを意味しないためです。この場合に完全に安全にするには、o.isDisposed()
を使用して、オブザーバブルがダウンストリームで終了したかどうかを確認する必要があります。onError
呼び出しが失われることを許可しないというポリシーがあるため、例外があります。オブザーバブルが既に終了している場合、ダウンストリームに配信されるか、グローバルUndeliverableException
としてスローされます。 Observableの作成者は、observableが終了して例外が発生した場合を「適切に」処理する必要があります。Observable
)とコンシューマー(Subscriber
)が一致しないことです。この場合、プロデューサーはコンシューマーよりも長生きしているため、プロデューサーでのみ問題を修正できます。前のコメントの@Kiskaeは、このような例外が発生する理由について正しく答えました。
このテーマに関する公式ドキュメントへのリンク: RxJava2-wiki 。
この動作を変更できない場合があるため、このUndeliverableException
を処理する方法があります。以下は、クラッシュと誤動作を回避する方法のコードスニペットです。
RxJavaPlugins.setErrorHandler(e -> {
if (e instanceof UndeliverableException) {
e = e.getCause();
}
if ((e instanceof IOException) || (e instanceof SocketException)) {
// fine, irrelevant network problem or API that throws on cancellation
return;
}
if (e instanceof InterruptedException) {
// fine, some blocking code was interrupted by a dispose call
return;
}
if ((e instanceof NullPointerException) || (e instanceof IllegalArgumentException)) {
// that's likely a bug in the application
Thread.currentThread().getUncaughtExceptionHandler()
.handleException(Thread.currentThread(), e);
return;
}
if (e instanceof IllegalStateException) {
// that's a bug in RxJava or in a custom operator
Thread.currentThread().getUncaughtExceptionHandler()
.handleException(Thread.currentThread(), e);
return;
}
Log.warning("Undeliverable exception received, not sure what to do", e);
});
上記のリンクから取られたこのコード。
重要な注意点。このアプローチは、グローバルエラーハンドラをRxJavaに設定するため、これらの例外を取り除くことができる場合は、より良いオプションです。