It is possible to stop a thread that is connecting

2019-06-18 04:52发布

问题:

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

回答1:

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
}


回答2:

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



回答3:

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().