I keep getting a java.net.SocketTimeoutException when attempting an OkHttp3 asynchronous Get. This suggests that I haven't set the read timeout value high enough (I think the default is 10 seconds).
The larger question is "How to prevent this exception?" but, unless someone has a better initial strategy, my immediate question is, "How to set a read timeout value for the request?"
In my code I've used the information from the Okttp Recipes page here
Notice the first two lines of my try-catch are commented out. That's because I cannot use the kind of builder (one capable of setting a timeout value, OkHttpClient.Builder) that I need in order to add header info (Request.Builder) .
My code looks like this:
m_client = new OkHttpClient();
try
{
//OkHttpClient.Builder bldr = m_client.newBuilder();
//bldr.readTimeout(0, TimeUnit.SECONDS);
Request.Builder reqBuilder = new Request.Builder();
reqBuilder.addHeader("authorization", getToken());
Request request = reqBuilder.url("http://plusdev.kooklah.com/api/v2_1/items/get").build();
m_client.newCall(request).enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
Log.i("Logit", "Inside onFailure() -- IOException: " + e.getMessage() + " ----- stack trace: " + UtilGen.exceptionToString(e));
runOnUiThread(new Runnable()
{
@Override
public void run()
{
// do stuff on UI thread
}
});
}
@Override
public void onResponse(Call call, final Response responseIn)
{
try
{
m_sServerResponse = responseIn.body().string();
}
catch (Exception ex)
{
Log.i("LogIt", " ---Inside onResponse() -- Exception occurred. ex: " + ex.toString());
}
runOnUiThread(new Runnable()
{
@Override
public void run()
{
Log.i("LogIt", " ---Inside onResponse() -- inside run().");
if (!m_sServerResponse.isEmpty())
{
Log.i("LogIt", " ---Inside onResponse() -- inside run() -- Success");
processDownloadedAssessments(m_sServerResponse);
}
}
});
}
});
}
catch (Exception ex)
{
Log.i("LogIt", "ex: " + ex.getMessage());
}
I found a reported issue that seems directly related, here, on the okhttp github site. There's even a recommendation to set the read timeout, which as mentioned above has been commented out because I cannot figure how to bring that kind of builder to bear on an async request as described on the Recipe page.
The stack trace for my exception is below, but be aware that most of the time I don't get the exception. Stack trace:
01-19 14:04:52.192: I/LogIt(25650): Inside onFailure() -- IOException: null ----- stack trace: java.net.SocketTimeoutException
01-19 14:04:52.192: I/LogIt(25650): at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
01-19 14:04:52.192: I/LogIt(25650): at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
01-19 14:04:52.192: I/LogIt(25650): at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
01-19 14:04:52.192: I/LogIt(25650): at okio.Okio$2.read(Okio.java:138)
01-19 14:04:52.192: I/LogIt(25650): at okio.AsyncTimeout$2.read(AsyncTimeout.java:236)
01-19 14:04:52.192: I/LogIt(25650): at okio.RealBufferedSource.indexOf(RealBufferedSource.java:325)
01-19 14:04:52.192: I/LogIt(25650): at okio.RealBufferedSource.indexOf(RealBufferedSource.java:314)
01-19 14:04:52.192: I/LogIt(25650): at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:210)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http1.Http1Codec.readResponse(Http1Codec.java:191)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:132)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:54)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)
01-19 14:04:52.192: I/LogIt(25650): at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
01-19 14:04:52.192: I/LogIt(25650): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
01-19 14:04:52.192: I/LogIt(25650): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
01-19 14:04:52.192: I/LogIt(25650): at java.lang.Thread.run(Thread.java:818)
Instead of
m_client = new OkHttpClient();
you should create the client using a builder like:
m_client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
When you create the client like this each Request
executed whit this client (using m_client.newCall(...)
) will use the timeouts specified in the builder.