问题
It's quite appealing to use Action(s) instead of a whole Subscriber when you only need OnNext() merely because it's more readable. But of course, errors happen and if you only use Action1 you'll get an Exception in your app. do operators can be of help here. I'm only concerned these two approaches are fully the same, please confirm or disconfirm. Any pitfalls?
The first approach:
Observable
.just(readFromDatabase())
.doOnError(new Action1<Throwable>() {
@Override public void call(Throwable throwable) {
// handle error
}
}).subscribe(new Action1<SomeData>() {
@Override public void call(SomeData someData) {
// react!
}
});
The second approach:
Observable
.just(readFromDatabase())
.subscribe(new Subscriber<SomeData>() {
@Override public void onCompleted() {
// do nothing
}
@Override public void onError(Throwable e) {
// handle error
}
@Override public void onNext(SomeData someData) {
// react!
}
});
Thank you!
回答1:
Both approaches aren't quite the same, and you're going to get some surprises out of the first:
First surprise will be that doOnError doesn't consume the error, but only performs some action on it. Consequently, in your case if the stream generates an error, it'll go through your doOnError code, and right after that trigger an OnErrorNotImplementedException, exactly as if the doOnError step wasn't there.
Let's say you realize that, and add an empty error handler to your subscribe call:
Observable
.just(readFromDatabase())
.doOnError(...)
.subscribe(..., error -> { /* already handled */ } );
Then you can meet the next subtle difference. do* blocks are considered part of the stream, which means that any uncatched exception in the block will result in a stream error (as opposed with exceptions thrown in 'onNext/OnError/onComplete' blocks, which get either ignored or immediately thrown, canceling the subscription on their way).
So in the above sample, if we say your database read triggers a stream error A, which gets passed to the doOnError block, which throws an exception B, then the (empty) subscription error handler we added will receive B (and only B).
The later difference isn't very concerning for doOnError (because anyway the stream gets terminated), but can be pretty surprising when occuring in doOnNext, where an exception has a very different behavior than the same exception thrown in subscribe onNext block (error'ed stream versus implicitly canceled stream).
来源:https://stackoverflow.com/questions/32889008/do-operators-instead-of-a-whole-subscriber