Working with URLConnection and Timeouts

One of the problems I encountered whilst developing my first Android app was getting a call to a web service to timeout if no response was received after around 10 seconds. Being primarily a .Net developer I was not too familiar with the various libraries and APIs of Java and Android. However it didn’t take long to find the URL and URLConnection classes. My first attempt used the URL class calling the openStream method and no timeout whatsoever:

This worked to a point but when, for whatever reason, an attempt to connect failed my app would just sit there forever. Of course, my code was inside an AsyncTask so the UI was never blocked but the task would never complete. So I turned my attention to the URLConnection class and found the setConnectTimeout method.

private String getResponse(URL url){
// given a url open a connection
URLConnection c = url.openConnection();
// set the connection timeout to 5 seconds
c.setConnectTimeout(5000);
// get a stream to read data from
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
// use the stream...
}

This time I created a URLConnection instance from the url passed to the method, set the timeout and then called openStream. I expected this to work but no. However, it turns out I had made a subtle mistake. Look at the last line and notice that I get a stream from the url instance. Seems a reasonable thing to do. However, doing it this way means the call to setConnectTimeout is ignored. If you create a URLConnection instance and set a timeout period then you also need to get a stream from the resulting connection object like this:

private String getResponse(URL url){
// given a url open a connection
URLConnection c = url.openConnection();
// set the connection timeout to 5 seconds
c.setConnectTimeout(5000);
// get a stream to read data from but this time from the connection instance
BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
// use the stream...
}

This is the correct way to do it but I still had a problem with the connection not timing out on occasion. The missing piece was a call to setReadTimeout:

private String getResponse(URL url){
// given a url open a connection
URLConnection c = url.openConnection();
// set the connection timeout to 5 seconds and the read timeout to 10 seconds
c.setConnectTimeout(5000);
c.setReadTimeout(10000);
// get a stream to read data from
BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()));
// use the stream...
}

The setConnectTimeout method is used in establishing a connection to the url whilst setReadTimeout is used in reading data on an already established connection, therefore there are two different reasons for a timeout to occur. You need to set explicit values for both as by default they are set to zero meaning they will never timeout. Either one could fail and your method would never return. With both timeouts set the code works as you would expect.

Android tip: The read timeout worked for me – got an IOException. The connection timeout works but I didn’t get an exception. getContentType() just returns null after timing out but getInputStream() generates a read timeout exception.