Можно ли остановить поток, который подключается к URL-адресу, с помощью httpConnection.connect()?

у меня есть поток, который подключается к 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.

спасибо


person Pableras84    schedule 05.10.2012    source источник
comment
Проблема здесь не в том, как остановить поток, а в том, почему тайм-ауты не работают. NB вам не нужно устанавливать их дважды. Объекты Connection и httpConnection остаются одним и тем же объектом.   -  person user207421    schedule 06.10.2012
comment
я пробовал все с тайм-аутами и не работал должным образом, я должен остановить поток также, когда пользователь нажимает клавишу «Назад», поэтому мне нужно узнать, как добиться этого   -  person Pableras84    schedule 06.10.2012
comment
Нет, вы должны заставить работать тайм-ауты. Вы действительно видите, что connect() выполняется более пяти секунд? Или это комбинация connect() и read()? Что здесь происходит на самом деле?   -  person user207421    schedule 06.10.2012
comment
Большая проблема здесь в том, что вы не хотите просто убить поток. Это так не работает.   -  person Kristopher Micinski    schedule 06.10.2012


Ответы (3)


Настройки тайм-аута в URLConnection недостаточны для обеспечения желаемого контроля тайм-аута. Причина в следующем:

  • setConnectTimeout() устанавливает время простоя для установления соединения с сервером. Таким образом, тайм-аут будет активирован только в том случае, если при открытии соединения соединение не может быть установлено в течение заданного периода времени.

  • setReadTimeount() устанавливает тайм-аут для чтения доступных данных. Для этого тайм-аут будет активирован только в том случае, если какая-либо одиночная операция чтения блокируется дольше установленного времени. Таким образом, вполне возможно, что даже при медленном соединении каждая операция чтения никогда не достигнет порога тайм-аута, но общее количество времени для чтения всех данных довольно велико.

Одним из решений для применения тайм-аута ко всей единице работы чтения является использование возможностей параллелизма, имеющихся в Java 5 и более поздних версиях. В частности, использование ExecutorService и Future должно быть достаточно.

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
}
person Brent Worden    schedule 06.10.2012
comment
Заранее извините за нубский вопрос... Разве запуск future.get() не побеждает цель запуска вашего кода в фоновом режиме? future.get должен блокировать свой текущий поток, который, вероятно, будет основным потоком. - person Jeremy Jao; 21.03.2019
comment
@JeremyJao, вы правы, утверждая, что get является блокирующим вызовом. Первоначальный вопрос касается того, как прервать загрузку, если она занимает слишком много времени. Это то, что выше пытается выполнить, выполняя фоновую задачу и ожидая ее завершения до установленного времени. Если блокировка вызывающего потока является проблемой, то вышеуказанное также необходимо каким-то образом выполнить в отдельном потоке. Я не чувствовал, что блокировка вызывающего потока была сутью исходного вопроса, поэтому я не обращался к нему в своем ответе. - person Brent Worden; 26.03.2019

Ответ Брента Уордена находится на правильном пути. Но есть проблема с его решением. Если истечет время ожидания задачи, поток, вызвавший future.get, получит исключение, как и ожидалось. Однако рабочий поток, выполнявший метод Runnable.run(), может зависнуть в ожидании завершения подключения или чтения.

Решить это сложно. Насколько мне известно, единственный надежный способ разблокировать поток, ожидающий подключения к сокету или чтения или записи потока сокета, — это вызвать close() для объекта Socket. И проблема с использованием этого подхода (здесь) заключается в том, что стандартный объект HttpUrlConnection не предоставляет объект Socket.

Я бы рекомендовал использовать клиентские библиотеки Apache Http. Этот вопрос объясняет, как отменить запрос, если вы используете HttpClient: Отменить запрос HttpClient

person Stephen C    schedule 06.10.2012

Вам нужно только вызвать 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().

person Alfredo Osorio    schedule 05.10.2012