httpConnection.connect() 方法可以停止连接 URL 的线程吗?

7

我有一个线程连接到一个URL,以获取一些数据。

有时候方法httpConnection.connect();花费的时间太长,我想将这个连接线程的加载对话框限制在5秒内。

我尝试在代码中添加了超时,但是它不起作用!!

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

因此,当过去5000秒或用户按下手机上的返回键时,我必须停止连接方法和线程。

如何实现这一点?我找不到有关在Android中使用URL连接线程执行此工作的信息。

谢谢


这里的问题不是如何停止线程,而是为什么超时不起作用。注意,您不需要设置两次。连接和httpConnection对象仍然是同一个对象。 - user207421
我尝试了所有的超时设置,但仍然无法正常工作。当用户按下返回键时,我必须停止线程,因此我需要学习如何实现这一点。 - Pableras84
不,你必须让超时时间起作用。你真的看到connect()执行了五秒钟以上吗?还是connect()和read()的组合?这里到底发生了什么? - user207421
2
这里更大的问题是,你不想“仅仅杀死”线程。它不是那样工作的。 - Kristopher Micinski
4个回答

3

URLConnection的超时设置无法提供所需的超时控制。原因是:

  • setConnectTimeout()仅设置与服务器建立连接的超时时间。因此,只有在打开连接时无法在规定的时间内建立连接时才会触发超时。

  • setReadTimeount()设置读取可用数据的超时时间。对于此操作,只有当任何单个读取操作阻塞的时间超过设置的时间限制时,才会触发超时。因此,在慢速连接上,每个读取操作从未接近超时阈值,但读取所有数据所需的总时间非常长,这是完全可能的。

将整个读取工作单元应用超时的一种解决方案是使用Java 5及以上版本中找到的并发能力。特别是使用ExecutorServiceFuture应该就足够了。

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
}

抱歉提前发出这个初学者问题...运行future.get()不是违背了在后台运行代码的目的吗?future.get应该会阻塞当前线程,很可能会是主线程。 - Jeremy Jao
@JeremyJao,你说“get”是一个阻塞调用是正确的。原始问题涉及如何在下载时间过长时中止下载。这就是上面代码尝试通过执行后台任务并等待其在规定时间内完成来实现的。如果调用线程的阻塞是一个问题,那么上述代码也需要以某种方式在单独的线程上执行。我没有感觉到调用线程的阻塞是原始问题的关键,所以我的回答没有涉及它。 - Brent Worden

3
Brent Worden的答案是正确的。但他的解决方案存在问题。如果任务超时,调用future.get的线程将像预期的那样收到异常。然而,执行Runnable.run()方法的工作线程可能仍然被卡在等待连接或读取完成的状态。
解决这个问题很困难。据我所知,解除等待套接字连接或套接字流读取或写入的线程的唯一可靠方式是在Socket对象上调用close()。而在这里使用这种方法的问题是,标准的HttpUrlConnection对象没有暴露Socket对象。
我的建议是使用Apache Http客户端库。此问题解释了如何在使用HttpClient时中止请求: 取消HttpClient请求

0

您只需要调用URLConnection.setConnectTimeout(millis)即可实现您所要求的功能。如果指定的超时时间到期,则会抛出SocketTimeoutException异常。

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
}

值得注意的是,它说的是以下内容:
一些非标准的实现可能会忽略指定的超时时间。要查看设置的连接超时时间,请调用getConnectTimeout()方法。

0

你不能这样做,如果你停止线程,它所属的进程也会结束。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接