简体   繁体   English

Robolectric + rxJava +改造第二次调用引发java.io.InterruptedIOException

[英]Robolectric + rxJava + retrofit Second call throws java.io.InterruptedIOException

I am developing and android app. 我正在开发和android应用程序。 I am using retrofit (with OkClient) for api requests and Robolectric for testing. 我正在对API请求使用翻新版(与OkClient配合使用),对Robolectric进行测试。 My api looks like this: 我的api看起来像这样:

@GET("/v1/book/{bookId}") Observable<Book> getBook(@Path("bookId") int bookId);

Just for Robolectric I am forcing api calls to be synchronous. 仅出于Robolectric,我要强制api调用同步。 The restAdapter builder looks like this: restAdapter构建器如下所示:

RestAdapter.Builder builder = new RestAdapter.Builder().setEndpoint(environment.getServerEndpoint())
                        .setClient(new OkClient(client))
                        .setExecutors(new ImmediateExecutor(), null)
                        .setErrorHandler(new ErrorHandler())
                        .setRequestInterceptor(new RequestInterceptor() {
                            @Override
                            public void intercept(RequestFacade request) {
                                // Always ask for JSON data
                                request.addHeader("Accept", "application/json");
                                request.addHeader("Content-Type", "application/json");               
                            }
                        });

public class ImmediateExecutor implements Executor {

        @Override public void execute(Runnable command) {
            command.run();
        }
    }

I have a simple test that looks like this: 我有一个简单的测试,看起来像这样:

API.getBook(1).subscribe();
API.getBook(2).subscribe();

Restadapter is created with the builder, and the API object with it (restadapter.create(...)). Restadapter是使用构建器以及API对象(restadapter.create(...))创建的。 I have omitted it as it is trivial. 我已经忽略了它,因为它很琐碎。

The first one works without problems, but the second one that should be the same throws an exception: 第一个工作正常,但第二个应该相同,但会引发异常:

java.io.InterruptedIOException
    at okio.Timeout.throwIfReached(Timeout.java:146)
    at okio.Okio$1.write(Okio.java:75)
    at okio.AsyncTimeout$1.write(AsyncTimeout.java:155)
    at okio.RealBufferedSink.flush(RealBufferedSink.java:201)
    at com.squareup.okhttp.internal.http.HttpConnection.flush(HttpConnection.java:140)
    at com.squareup.okhttp.internal.http.HttpTransport.finishRequest(HttpTransport.java:52)
    at com.squareup.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:828)
    at com.squareup.okhttp.internal.http.HttpEngine.access$200(HttpEngine.java:95)
    at com.squareup.okhttp.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:823)
    at com.carmacarpool.carmaridepool.rest.CarmaHttpClientFactory$NetworkLoggingInterceptor.intercept(CarmaHttpClientFactory.java:77)
    at com.squareup.okhttp.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:803)
    at com.squareup.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:684)
    at com.squareup.okhttp.Call.getResponse(Call.java:272)
    at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:228)
    at com.carmacarpool.carmaridepool.rest.CarmaHttpClientFactory$LoggingInterceptor.intercept(CarmaHttpClientFactory.java:53)
    at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:225)
    at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:199)
    at com.squareup.okhttp.Call.execute(Call.java:79)
    at retrofit.client.OkClient.execute(OkClient.java:53)
    at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
    at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
    at retrofit.RestAdapter$RestHandler$1.invoke(RestAdapter.java:265)
    at retrofit.RxSupport$2.run(RxSupport.java:55)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at com.carmacarpool.carmaridepool.testutils.ShadowUICarmaRESTClassFactory$ImmediateExecutor.execute(ShadowUICarmaRESTClassFactory.java:91)
    at retrofit.RxSupport$1.call(RxSupport.java:42)
    at retrofit.RxSupport$1.call(RxSupport.java:32)
    at rx.Observable.subscribe(Observable.java:7393)
    at rx.Observable.subscribe(Observable.java:7083)
    at com.carmacarpool.carmaridepool.CorridorTest.test(CorridorTest.java:99)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:265)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:205)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:173)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

I have one network interceptor just with a log and it works ok. 我只有一个带有日志的网络拦截器,它可以正常工作。 I have access to the server logs, and the request is not even reaching the server. 我有权访问服务器日志,请求甚至没有到达服务器。

Does anybody have any clue about what could be the problem? 有人对可能的问题有任何线索吗? It seems that for some unknown reason the thread is being killed? 似乎由于某种未知原因,线程被杀死了?

Thanks. 谢谢。

EDIT : If in the onNext function (first parameter of subscribe), I execute the second request, then it works. 编辑 :如果在onNext函数(订阅的第一个参数),我执行第二个请求,然后它可以工作。 Everything is synchronous as expected. 一切都按预期进行了同步。

SOLUTION After many tries I could find a solution. 解决方案经过多次尝试,我找到了解决方案。 The problem seems to be coming from Okio. 问题似乎来自Okio。 Apparently there is a buffer that writes the response (or something like this, I solved it a few weeks ago and I don't remember 100%). 显然有一个写响应的缓冲区(或类似的东西,我几周前解决了,我不记得是100%)。 This buffer gets closed in the middle of the second request and that's what is causing the error. 该缓冲区在第二个请求的中间被关闭,这就是导致错误的原因。

To fix this what I do is wrap the request in a try/catch block. 要解决此问题,我将请求包装在try / catch块中。 If an IOException happens then I retry. 如果发生IOException,则重试。 I am retrying a maximum of 5 times (to avoid infinite loops). 我最多重试5次(以避免无限循环)。

The code looks like: 代码如下:

  try { // Perform the request return chain.proceed(request); } catch (IOException e) { // Retry again if we haven't tried at least REQUEST_RETRIES times if (iteration < REQUEST_RETRIES) { return performRequest(chain, ++iteration); } // Otherwise, save the exception and throw it later exception = e; } 

The chain object comes from an OkHttpClient interceptor: 链对象来自OkHttpClient拦截器:

OkHttpClient client = new OkHttpClient(); OkHttpClient客户端=新的OkHttpClient(); client.interceptors().add(new CustomInterceptor()); client.interceptors()。add(new CustomInterceptor());

private class CustomInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { ... 私有类CustomInterceptor实现了Interceptor {@Override public Response拦截(链)抛出IOException {...

Hope this is helpful. 希望这会有所帮助。

I think you're doing a little too much to get observables to run synchronously during testing. 我认为您所做的工作太多了,无法在测试过程中使可观察到的同步运行。 Instead all you need to do is during your test 相反,您需要做的只是在测试期间

 Book book = retrofitAPI.getBook(someId).toBlocking.first()

This would execute the observable synchronously. 这将同步执行可观察的。 One of my favorite parts of the Rx library. 我最喜欢的Rx库之一。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在使用RxJava2和Retrofit在android中实现即时搜索时获取java.io.InterruptedIOException - getting java.io.InterruptedIOException while implementing instant search in android using RxJava2 and Retrofit 致命异常:java.io.InterruptedIOException:线程在使用 rxjava 改造时中断 - Fatal Exception: java.io.InterruptedIOException: thread interrupted while using retrofit with rxjava 不断收到 java.io.InterruptedIOException:Retrofit2 中的超时 - Keep getting java.io.InterruptedIOException: timeout in Retrofit2 改造多部分图像上传问题Retrofit.RetrofitError java.io.InterruptedIOException - Retrofit Multipart Image Upload issue retrofit.RetrofitError java.io.InterruptedIOException Android Volley NoConnectionError:java.io.InterruptedIOException - Android Volley NoConnectionError: java.io.InterruptedIOException io.reactivex.exceptions.UndeliverableException:java.io.InterruptedIOException - io.reactivex.exceptions.UndeliverableException: java.io.InterruptedIOException 随机com.android.volley.NoConnection错误,java.io.InterruptedIOException,statuscode = 0 - random com.android.volley.NoConnection error, java.io.InterruptedIOException, statuscode=0 Java RxJAva / Retrofit / OkHttp组合看似随机InterruptedIOException - Java RxJAva/Retrofit/OkHttp combination seemingly random InterruptedIOException RxTextView文本更改+改造调用导致InterruptedIOException - RxTextView text changes + retrofit call leads to InterruptedIOException retrofit2 和 rxjava3:java.lang.IllegalArgumentException:找不到 io.reactivex.rxjava3.core.Observable 的调用适配器 - retrofit2 and rxjava3: java.lang.IllegalArgumentException: Could not locate call adapter for io.reactivex.rxjava3.core.Observable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM