我有以下代码块:
try {
URL url = new URL("http://site-to-test.com/nonexistingpage.html");
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
urlc.setRequestProperty("User-Agent", CoreProtocolPNames.USER_AGENT);
urlc.setRequestProperty("Connection", "close");
urlc.setConnectTimeout(500); // timeout is in milliseconds
urlc.connect();
if (urlc.getResponseCode() == 404) {
// Server was reachable
Log.i(TAG, "Server is reachable");
}
} catch (MalformedURLException mue) {
Log.e(TAG, "MalformedURLException: " + mue.getMessage());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.getMessage());
}
当无法通过当前网络访问site-to-test
域时,此代码会在收到IOException
之前阻塞大约30-40秒。我特意将超时值设置为500毫秒。我在这里错过了什么?无论网络状态和网站的可用性如何,上述块是否应该在半秒内终止?
答案 0 :(得分:13)
似乎是Java URLConnection provides no fail-safe timeout on reads
正如文章所解释的那样,解决方案是使用单独的Thread进行计时,并在完成计时器线程后手动断开HttpURLConnection。
答案 1 :(得分:1)
经过深入调查和大量的跟踪后,我发现实现AsyncTask(或Service,用于执行后台工作的对象)的计时器远离HTTP连接类的最佳方法,就像有时断开HTTP连接一样连接,这不会中断Web调用,我实现了这个类,当您需要对HTTP连接进行超时检查时使用
public abstract class AsyncTaskWithTimer<Params, Progress, Result> extends
AsyncTask<Params, Progress, Result> {
private static final int HTTP_REQUEST_TIMEOUT = 30000;
@Override
protected Result doInBackground(Params... params) {
createTimeoutListener();
return doInBackgroundImpl(params);
}
private void createTimeoutListener() {
Thread timeout = new Thread() {
public void run() {
Looper.prepare();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (AsyncTaskWithTimer.this != null
&& AsyncTaskWithTimer.this.getStatus() != Status.FINISHED)
AsyncTaskWithTimer.this.cancel(true);
handler.removeCallbacks(this);
Looper.myLooper().quit();
}
}, HTTP_REQUEST_TIMEOUT);
Looper.loop();
}
};
timeout.start();
}
abstract protected Result doInBackgroundImpl(Params... params);
}
此示例
public class AsyncTaskWithTimerSample extends AsyncTaskWithTimer<Void, Void, Void> {
@Override
protected void onCancelled(Void void) {
Log.d(TAG, "Async Task onCancelled With Result");
super.onCancelled(result);
}
@Override
protected void onCancelled() {
Log.d(TAG, "Async Task onCancelled");
super.onCancelled();
}
@Override
protected Void doInBackgroundImpl(Void... params) {
// Do background work
return null;
};
}