我想知道如何忽略异常并继续无限流(在我的情况下是位置流)?
我获取当前用户位置(使用Android-ReactiveLocation),然后将其发送到我的API(使用Retrofit)。
在我的情况下,当在网络调用(例如超时)期间发生异常时,会调用onError
方法并且流会自行停止。如何避免呢?
的活动:
private RestService mRestService;
private Subscription mSubscription;
private LocationRequest mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(100);
...
private void start() {
mRestService = ...;
ReactiveLocationProvider reactiveLocationProvider = new ReactiveLocationProvider(this);
mSubscription = reactiveLocationProvider.getUpdatedLocation(mLocationRequest)
.buffer(50)
.flatMap(locations -> mRestService.postLocations(locations)) // can throw exception
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
}
RestService:
public interface RestService {
@POST("/.../")
Observable<Response> postLocations(@Body List<Location> locations);
}
答案 0 :(得分:49)
您可能想要使用其中一个error handling operators。
onErrorResumeNext( )
- 指示Observable在遇到错误时发出一系列项目onErrorReturn( )
- 指示Observable在遇到错误时发出特定项目onExceptionResumeNext( )
- 指示Observable在遇到异常后继续发出项目(但不是其他类型的throwable)retry( )
- 如果来源Observable发出错误,请重新订阅,希望它能完整而不会出错retryWhen( )
- 如果源Observable发出错误,请将该错误传递给另一个Observable以确定是否重新订阅源 Especialy retry
和onExceptionResumeNext
看起来很有希望。
答案 1 :(得分:13)
mRestService.postLocations(locations)
发出一个项目,然后完成。
如果发生错误,则会发出错误,从而完成流。
当您在flatMap
中调用此方法时,错误将继续显示在&#34; main&#34;流,然后您的流停止。
您可以做的是将您的错误转换为另一个项目(如此处所述:https://stackoverflow.com/a/28971140/476690),但不在主流上(我认为您已尝试过)但在mRestService.postLocations(locations)
上。
这样,此调用将发出错误,该错误将转换为项目/另一个observable,然后完成。 (不调用onError
)。
在消费者视图中,mRestService.postLocations(locations)
将发出一个项目,然后完成,就像一切都成功一样。
mSubscription = reactiveLocationProvider.getUpdatedLocation(mLocationRequest)
.buffer(50)
.flatMap(locations -> mRestService.postLocations(locations).onErrorReturn((e) -> Collections.emptyList()) // can't throw exception
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
答案 2 :(得分:6)
只需粘贴来自@ MikeN的链接信息即可丢失:
import rx.Observable.Operator;
import rx.functions.Action1;
public final class OperatorSuppressError<T> implements Operator<T, T> {
final Action1<Throwable> onError;
public OperatorSuppressError(Action1<Throwable> onError) {
this.onError = onError;
}
@Override
public Subscriber<? super T> call(final Subscriber<? super T> t1) {
return new Subscriber<T>(t1) {
@Override
public void onNext(T t) {
t1.onNext(t);
}
@Override
public void onError(Throwable e) {
onError.call(e);
}
@Override
public void onCompleted() {
t1.onCompleted();
}
};
}
}
并将其用于可观察源附近,因为其他运营商可能会这样做 在此之前急切地取消订阅。
Observerable.create(connectToUnboundedStream()).lift(new OperatorSuppressError(log()).doOnNext(someStuff()).subscribe();
但请注意,这会抑制错误传递 资源。如果在引发异常后链中的任何onNext,则为 仍有可能取消订阅来源。
答案 3 :(得分:6)
如果您只想忽略flatMap
中的错误而不返回元素,请执行以下操作:
flatMap(item ->
restService.getSomething(item).onErrorResumeNext(Observable.empty())
);
答案 4 :(得分:1)
尝试在Observable.defer调用中调用rest服务。这样,对于每次调用,您都有机会使用自己的'onErrorResumeNext'并且错误不会导致主流完成。
reactiveLocationProvider.getUpdatedLocation(mLocationRequest)
.buffer(50)
.flatMap(locations ->
Observable.defer(() -> mRestService.postLocations(locations))
.onErrorResumeNext(<SOME_DEFAULT_TO_REACT_TO>)
)
........
该解决方案最初来自此主题 - &gt; RxJava Observable and Subscriber for skipping exception?,但我认为它也适用于你的情况。
答案 5 :(得分:1)
为此问题添加我的解决方案:
privider
.compose(ignoreErrorsTransformer)
.subscribe()
private final Observable.Transformer<ResultType, ResultType> ignoreErrorsTransformer =
new Observable.Transformer<ResultType, ResultType>() {
@Override
public Observable<ResultType> call(Observable<ResultType> resultTypeObservable) {
return resultTypeObservable
.materialize()
.filter(new Func1<Notification<ResultType>, Boolean>() {
@Override
public Boolean call(Notification<ResultType> resultTypeNotification) {
return !resultTypeNotification.isOnError();
}
})
.dematerialize();
}
};
答案 6 :(得分:0)
稍微修改解决方案(@MikeN)以启用有限流:
import rx.Observable.Operator;
import rx.functions.Action1;
public final class OperatorSuppressError<T> implements Operator<T, T> {
final Action1<Throwable> onError;
public OperatorSuppressError(Action1<Throwable> onError) {
this.onError = onError;
}
@Override
public Subscriber<? super T> call(final Subscriber<? super T> t1) {
return new Subscriber<T>(t1) {
@Override
public void onNext(T t) {
t1.onNext(t);
}
@Override
public void onError(Throwable e) {
onError.call(e);
//this will allow finite streams to complete
t1.onCompleted();
}
@Override
public void onCompleted() {
t1.onCompleted();
}
};
}
}
答案 7 :(得分:0)
这是我的Kotlin扩展函数,用于忽略错误
fun <T> Observable<T>.ignoreErrors(errorHandler: (Throwable) -> Unit) =
retryWhen { errors ->
errors
.doOnNext { errorHandler(it) }
.map { 0 }
}
这利用retryWhen
无限期地重新订阅上游,同时仍然允许您以非终端方式处理错误。
这很危险
答案 8 :(得分:0)
使用Rxjava2,我们可以使用delayErrors参数调用重载的平面图: flatmap javadoc
将其正确传递时:
当前Flowable和所有内部发布者的异常被延迟,直到所有它们都为false终止为止,第一个发出异常信号将立即终止整个序列
答案 9 :(得分:0)
这个答案可能有点晚了,但是如果有人偶然发现了这个问题,那么不用重新发明轮子,而是可以使用Jacke Wharton的即用型中继库
https://github.com/JakeWharton/RxRelay
有很好的文档,但是从本质上讲,Relay是一个Subject,除了不能调用onComplete或onError。
,选项为:
行为继电器
Relay that emits the most recent item it has observed and all subsequent observed items to each subscribed Observer.
// observer will receive all events.
BehaviorRelay<Object> relay = BehaviorRelay.createDefault("default");
relay.subscribe(observer);
relay.accept("one");
relay.accept("two");
relay.accept("three");
// observer will receive the "one", "two" and "three" events, but not "zero"
BehaviorRelay<Object> relay = BehaviorRelay.createDefault("default");
relay.accept("zero");
relay.accept("one");
relay.subscribe(observer);
relay.accept("two");
relay.accept("three");
PublishRelay 观察者订阅后,将随后观察到的所有项目都发送给订阅者的中继。
PublishRelay<Object> relay = PublishRelay.create();
// observer1 will receive all events
relay.subscribe(observer1);
relay.accept("one");
relay.accept("two");
// observer2 will only receive "three"
relay.subscribe(observer2);
relay.accept("three");
ReplayRelay 中继会缓冲它观察到的所有项目,并将它们重放到任何订阅的观察者。
ReplayRelay<Object> relay = ReplayRelay.create();
relay.accept("one");
relay.accept("two");
relay.accept("three");
// both of the following will get the events from above
relay.subscribe(observer1);
relay.subscribe(observer2);
答案 10 :(得分:0)
您可以使用 onErrorComplete() 方法跳过错误
mSubscription = reactiveLocationProvider.getUpdatedLocation(mLocationRequest)
.buffer(50)
.flatMapMaybe(locations -> Maybe.just(mRestService.postLocations(locations).onErrorComplete()) // skip item
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();