i have a thread that is connecting to a url to obtaining some data.
Sometimes the method httpConnection.connect();
taked too munch time to get the response, and i want to limit the loading dialog of this connection thread to 5 seg.
I tryed adding timeouts into the code, but it doesn't work!!
URL formattedUrl = new URL(url);
URLConnection connection = formattedUrl.openConnection();
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setAllowUserInteraction(false);
httpConnection.setInstanceFollowRedirects(true);
httpConnection.setRequestMethod("GET");
httpConnection.setConnectTimeout(5000);
httpConnection.setReadTimeout(5000);
httpConnection.connect();
So, i must stop the connect method and the thread when 5000 seconds have passed or when the used has pressed the back key on the phone.
How can this be achieved? i can't find info about doing this work in android with a url connection thread.
thanks
The timeout settings on URLConnection are not sufficient to provide the timeout control desired. The reason being is:
setConnectTimeout() sets the timeout for just establishing a connection with the server. So, a timeout will only be triggered if when opening the connection, the connection can not be established in the prescribed amount of time.
setReadTimeount() sets the timeout for reading available data. For this, a timeout will only be triggered if any, single read operation blocks for longer than the set amount of time. So, it is quite possible even on a slow connection that each read operation never approaches the timeout threshold but, the total amount of time to read all the data is quite lengthly.
One solution to apply a timeout to the entire read unit of work, is to use the concurrency capabilities found in Java 5 and beyond. In particular, the use of an ExecutorService and Future should be sufficient.
Runnable task = new Runnable() {
public void run() {
// original code to read data from a URL
}
};
ExecutorService executor = Executors.newSingleThreadExecutor(); // or any other implementation
Future<?> future = executor.submit(task);
try {
future.get(5, TimeUnit.SECONDS); // wait 5 seconds for task to complete
// success
} catch (TimeoutException ex) {
// handle timeout
} finally {
executor.shutdownNow(); // cleanup
}
Brent Worden's answer is on the right track. But there is a problem with his solution. If the task timeout kicks in, the thread that called future.get
will get an exception as expected. However, the worker thread that was executing the Runnable.run()
method may still be stuck waiting for the connect or read to complete.
Solving this is difficult. As far as I'm aware, the only reliable way to unjam a thread that is waiting on a socket connect or socket stream read or write is to call close()
on the Socket
object. And the problem with using that approach (here) is that the standard HttpUrlConnection
object doesn't expose the Socket
object.
My recommendation would be to use the Apache Http client libraries. This question explains how to abort a request if you use HttpClient: Cancel an HttpClient request
You only need to invoke the URLConnection.setConnectTimeout(millis) to achieve what you asking. If the specified timeout expires a SocketTimeoutException is thrown.
try {
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setConnectTimeout(5000); //set timeout to 5 seconds
} catch (java.net.SocketTimeoutException e) {
//DO SOMETHING
} catch (java.io.IOException e) {
//DO SOMETHING
}
It's worth noting that it says the following:
Some non-standard implmentation of this method may ignore the
specified timeout. To see the connect timeout set, please call
getConnectTimeout().