【问题标题】:getting java.io.InterruptedIOException while implementing instant search in android using RxJava2 and Retrofit使用 RxJava2 和 Retrofit 在 android 中实现即时搜索时获取 java.io.InterruptedIOException
【发布时间】:2018-03-21 13:31:13
【问题描述】:

所以我正在尝试使用 rxjava2 和改造来实现即时搜索, 该过程很简单,只要用户更改文本publish.onNext() 就会被调用(发布是PublishSubject 对象)。 我添加了过滤器和去抖动以及切换映射运算符,以便在文本长度大于阈值并且没有同时使用连续输入进行调用时从服务器进行搜索。

这是代码:

subject = PublishSubject.create();
    getCompositeDisposable().add(subject
            .filter(s -> s.length() >= 3)
            .debounce(300,
                    TimeUnit.MILLISECONDS)
            .switchMap(s -> getDataManager().getHosts(
                    getDataManager().getDeviceToken(),
                    s).observeOn(Schedulers.io()))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe(hostResponses -> {
                getMvpView().hideEditLoading();
                if (hostResponses.size() != 0) {
                    if (this.hostResponses != null)
                        this.hostResponses.clear();
                    this.hostResponses = hostResponses;
                    getMvpView().setHostView(getHosts(hostResponses));
                } else {
                    getMvpView().onFieldError("No host found");
                }

            }, throwable -> {
                getMvpView().hideEditLoading();
                if (throwable instanceof HttpException) {
                   HttpException exception = (HttpException)throwable;
                    if (exception.code() == 401) {
                        getMvpView().onError(R.string.code_expired,
                                BaseUtils.TOKEN_EXPIRY_TAG);
                    }
                }

            })
    );

现在我的代码运行良好,我正在实现我所需要的 但是当我输入一个长字符串并按下退格按钮时出现错误,发生的情况是当我的 AutoCompleteTextView 的文本被清除时,会引发异常

这是异常的堆栈跟踪:

java.io.InterruptedIOException: thread interrupted  
at okio.Timeout.throwIfReached(Timeout.java:145)  
at okio.Okio$1.write(Okio.java:76)  
at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)  
at okio.RealBufferedSink.flush(RealBufferedSink.java:216)  
at okhttp3.internal.http1.Http1Codec.finishRequest(Http1Codec.java:166)  
at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:84) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)  
at com.facebook.stetho.okhttp3.StethoInterceptor.intercept(StethoInterceptor.java:56)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)  
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)  
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)  
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)  
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:125)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)  
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)  
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)  
at okhttp3.RealCall.execute(RealCall.java:77)  
at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)  
at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:41)  
at io.reactivex.Observable.subscribe(Observable.java:10700)  
at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)  
at io.reactivex.Observable.subscribe(Observable.java:10700)  
at io.reactivex.internal.operators.observable.ObservableObserveOn.subscribeActual(ObservableObserveOn.java:45)  
at io.reactivex.Observable.subscribe(Observable.java:10700)  
at io.reactivex.internal.operators.observable.ObservableSwitchMap$SwitchMapObserver.onNext(ObservableSwitchMap.java:126)  
at io.reactivex.observers.SerializedObserver.onNext(SerializedObserver.java:111)  
at io.reactivex.internal.operators.observable.ObservableDebounceTimed$DebounceTimedObserver.emit(ObservableDebounceTimed.java:140)  
at io.reactivex.internal.operators.observable.ObservableDebounceTimed$DebounceEmitter.run(ObservableDebounceTimed.java:165)  
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)  
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)  
at java.util.concurrent.FutureTask.run(FutureTask.java:237)  
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)  
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)  
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)  
at java.lang.Thread.run(Thread.java:762

【问题讨论】:

  • 这是一种不幸的情况,许多阻塞 IO API 如果它们的连接/活动被异步取消,就会抛出异常。除了安装global error handler 以防止整个应用程序崩溃之外,您可能无能为力。
  • 问题不在于应用程序崩溃或其他原因,而是一旦引发此异常,线程(很可能是 Schedulers.io())就会被中断,然后当用户进入搜索时查询没有任何反应,我该如何解决?

标签: java android retrofit2 rx-java2


【解决方案1】:

内部observeOn(Schedulers.io()) 看起来不正确,因为在那之后您立即将元素移回主线程。应该是subscribeOn(Schedulers.io())

同时删除 subscribeOn() 调用之前的 subscribe 调用,因为它应该没有实际效果,因为链订阅了顶部的 PublishSubject

.switchMap(s -> getDataManager()
               .getHosts(getDataManager().getDeviceToken(), s)
//             .observeOn(Schedulers.io())
               .subscribeOn(Schedulers.io())   // <-------------------------
)
.observeOn(AndroidSchedulers.mainThread())
//.subscribeOn(Schedulers.io())   // <--------------------------------------
.subscribe(hostResponses -> {

【讨论】:

  • 好吧,我错误地在我理解和实现的 switchmap 中使用了 observeOn 而不是 subscribeOn,这是我从一开始就打算做的(当我遇到这个问题时),并且在这种情况下,在订阅之前使用 subscribeon变得多余,但假设我没有在我的 switchmap 中添加 subscribeOn 并在订阅外部之前使用它,这种方法与前一种方法有何不同,因为我在网络调用中默认使用后一种方法?
  • 顺便说一句,您的解决方案有效,谢谢!我只是好奇如何在 switchmap 内部而不是外部调用 subscribeOn 来解决这个线程中断异常
  • subscribeOn 会影响 订阅时间 副作用,Retrofit 会在那时执行其网络操作。因为你有switchMap,它每次都会创建一个新的源,因此每次有一个要映射的上游项目时都会有一个新的订阅时间。如果它在这样的映射器之外,它可能没有真正的效果。您通常会得到 NetworkOnMainThreadException,但在您的情况下,debounce 及其 computation Scheduler 发射将网络调用移到 UI 线程之外。
  • 好的!我现在明白了,那是有见地的。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-06
  • 2021-06-24
  • 2018-12-11
  • 2020-05-27
  • 2011-05-15
  • 2017-01-26
  • 1970-01-01
相关资源
最近更新 更多