【问题标题】:RxTextView text changes + retrofit call leads to InterruptedIOExceptionRxTextView 文本更改 + 改造调用导致 InterruptedIOException
【发布时间】:2016-05-24 21:07:48
【问题描述】:

许多带有RxTextView.textChanges 示例和debounce 的RxJava 教程都使用“实时搜索”。例如:Improving UX with RxJava。所以我已经实现了这个例子,我试着玩一下:

RxTextView.textChanges(searchView)
          .observeOn(Schedulers.io())
          .skip(1)
          .debounce(DELAY_BEFORE_REQUEST_MS, TimeUnit.MILLISECONDS)
          .map(new Func1<CharSequence, String>() {
                @Override public String call(CharSequence charSequence) {
                    return charSequence.toString();
                }
            })
          .switchMap(new Func1<String, Observable<Response>>() {
                @Override public Observable<Response> call(String query) {
                    return retrofitService.search(query);
                }
            })
          .subscribe();

一切看起来都不错,直到我决定在 Android 模拟器上模拟 GPRS 网络类型。

触发了第一个 api 调用,当我将下一个字母添加到“searchView”时,应用程序崩溃并显示InterruptedIOException

java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add `onError` handling.
      at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:60)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
      at java.util.concurrent.FutureTask.run(FutureTask.java:237)
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
      at java.lang.Thread.run(Thread.java:818)
   Caused by: rx.exceptions.OnErrorNotImplementedException: thread interrupted
      at rx.Observable$27.onError(Observable.java:7923)
      at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:159)
      at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:120)
      at rx.internal.operators.OperatorSubscribeOn$1$1$1.onError(OperatorSubscribeOn.java:71)
      at rx.observers.SerializedObserver.onError(SerializedObserver.java:159)
      at rx.observers.SerializedSubscriber.onError(SerializedSubscriber.java:79)
      at rx.internal.operators.OperatorSwitch$SwitchSubscriber.error(OperatorSwitch.java:223)
      at rx.internal.operators.OperatorSwitch$InnerSubscriber.onError(OperatorSwitch.java:282)
      at rx.internal.operators.OperatorMerge$MergeSubscriber.reportError(OperatorMerge.java:240)
      at rx.internal.operators.OperatorMerge$MergeSubscriber.checkTerminate(OperatorMerge.java:776)
      at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:537)
      at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:526)
      at rx.internal.operators.OperatorMerge$MergeSubscriber.onError(OperatorMerge.java:250)
      at rx.internal.operators.OperatorMap$1.onError(OperatorMap.java:48)
      at retrofit2.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:114)
      at retrofit2.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:88)
      at rx.Observable$2.call(Observable.java:162)
      at rx.Observable$2.call(Observable.java:154)
      at rx.Observable$2.call(Observable.java:162)
      at rx.Observable$2.call(Observable.java:154)
      at rx.Observable.unsafeSubscribe(Observable.java:8098)
      at rx.internal.operators.OperatorSwitch$SwitchSubscriber.onNext(OperatorSwitch.java:105)
      at rx.internal.operators.OperatorSwitch$SwitchSubscriber.onNext(OperatorSwitch.java:60)
      at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:54)
      at rx.internal.operators.OperatorDoOnEach$1.onNext(OperatorDoOnEach.java:85)
      at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:54)
      at rx.observers.SerializedObserver.onNext(SerializedObserver.java:95)
      at rx.observers.SerializedSubscriber.onNext(SerializedSubscriber.java:95)
      at rx.internal.operators.OperatorDebounceWithTime$DebounceState.emit(OperatorDebounceWithTime.java:132)
      at rx.internal.operators.OperatorDebounceWithTime$1$1.call(OperatorDebounceWithTime.java:79)
      at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) 
      at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269) 
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
      at java.lang.Thread.run(Thread.java:818) 
   Caused by: java.io.InterruptedIOException: thread interrupted
      at okio.Timeout.throwIfReached(Timeout.java:145)
      at okio.Okio$2.read(Okio.java:136)
      at okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
      at okio.RealBufferedSource.indexOf(RealBufferedSource.java:306)
      at okio.RealBufferedSource.indexOf(RealBufferedSource.java:300)
      at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:196)
      at okhttp3.internal.http.Http1xStream.readResponse(Http1xStream.java:184)
      at okhttp3.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:125)
      at okhttp3.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:723)
      at okhttp3.internal.http.HttpEngine.access$200(HttpEngine.java:81)
      at okhttp3.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:708)
      at okhttp3.internal.http.HttpEngine.readResponse(HttpEngine.java:563)
    at okhttp3.RealCall.ge

我搜索了一下,看来我并不孤单:firstsecond

第一个问题的作者通过使用 try-catch 块包装改造请求解决了这个问题。 对我来说,这是试图掩盖糟糕的架构。我正在寻找更清洁的解决方案。

有没有办法忽略第一个 API 调用结果,并使用 RxJava 启动新的?或者我应该尝试切换新的 Retrofit Call API,并尝试取消先前的请求(并打破反应式方法)?

我使用的是 Retrofit 2 beta 3,带有最新的 Okio 和 OkHttp。

【问题讨论】:

标签: android rx-java retrofit2


【解决方案1】:

嗯,错误非常明确,您应该添加onError 处理。它可能看起来像这样:

.subscribe(new Observer<Response>() {
    @Override
    public void onCompleted() {
    }

    @Override
    public void onError(Throwable e) {
    }

    @Override
    public void onNext(Response response) {
    }
});

但是,一旦发出错误,您的订阅将被终止,但您可以通过如下处理 API 调用的错误来避免这种情况:

.switchMap(new Func1<String, Observable<Response>>() {
    @Override public Observable<Response> call(String query) {
        return retrofitService.search(query)
                .onErrorResumeNext(Observable.<Response>empty());
    }
})

【讨论】:

  • 是的,我知道错误处理,我已经把它剪掉了。我不想吞下异常,而是想阻止它。
  • 我猜你可以用flatMap代替switchMap,这样之前的Observable就不会被取消订阅,InterruptedIOException也不会再被抛出了。但是,例如,当网络出现故障时,您仍然会遇到类似的问题。所以你不能阻止所有的异常,使用onErrorResumeNext 对我来说看起来很干净。至少,它比 try-catch 块更干净。
  • FlatMap 在这里没有帮助 - 同样的错误。在普通代码中,我有错误处理。我知道网络异常。这是未经检查的异常与检查的异常。有些我想使用 onError(网络),其中一些需要防止代码(IOException)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-13
  • 1970-01-01
  • 2021-02-17
  • 1970-01-01
  • 1970-01-01
  • 2020-01-22
相关资源
最近更新 更多