Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why timeout value is not respected by android HttpURLConnection?

I have the following code block:

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

When the site-to-test domain is not reachable through the current network, this code blocks for about 30-40 seconds before receiving the IOException. And I specifically set the timeout value to 500ms. What am I missing here? Shouldn't the above block terminate in half a second, regardless of the network state and the site's availability?

like image 681
András Szepesházi Avatar asked Jul 04 '12 12:07

András Szepesházi


People also ask

What is the default timeout for HttpURLConnection?

Appears the "default" timeouts for HttpURLConnection are zero which means "no timeout."

What is HttpURLConnection in android?

HttpsURLConnection. HttpsURLConnection. HttpsURLConnection extends HttpURLConnection with support for https-specific features. The abstract class URLConnection is the superclass of all classes that represent a communications link between the application and a URL.

What is setConnectTimeout in Java?

public void setConnectTimeout(int timeout) Sets a specified timeout value, in milliseconds, to be used when opening a communications link to the resource referenced by this URLConnection. If the timeout expires before the connection can be established, a java.

How do I close HttpURLConnection?

If client does not call close() , call disconnect() will close the InputStream and close the Socket . So in order to reuse the Socket , just call InputStream. close() .


2 Answers

It appears that Java URLConnection provides no fail-safe timeout on reads

The solution is, as the article explains, to use a separate Thread for timing, and disconnect the HttpURLConnection manually once the timer thread is done.

like image 83
András Szepesházi Avatar answered Oct 02 '22 16:10

András Szepesházi


After deep investigations and alot of trails, I found that the best way to implement a timer for AsyncTask (or Service, the object you used to perform background work) away from the HTTP connection class, as sometimes when you disconnect the HTTP connection, this doesn't interrupt the web call, I implemented this class to be used when you need timeout check for your HTTP connection

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

A Sample for this

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;
    };
 }
like image 22
Ayman Mahgoub Avatar answered Oct 02 '22 16:10

Ayman Mahgoub