Android ignores DefaultHttpClient timeout parameter

I am stuck with a timeout issue with DefaultHttpClient on Android. I am trying to set a timeout using the following piece of code:

HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 4000);
HttpConnectionParams.setSoTimeout(httpParameters, 4000);

      

But if the device is connected to a network without an internet connection, the timeout never starts and the execution of the HTTP request never throws a timeout exception. I am making an HTTP request like this:

HttpResponse httpResponse = client.execute(request);

      

I also tried setting a timeout on the HttpRequest with the following lines:

HttpRequestBase request = ...
request.setParams(httpParameters);

      

Android seems to ignore the timeout settings and when making an HTTP request on a network without an internet connection, all requests fail after 20 seconds, not after my timeout settings.

I have also tried to close all internet connections and abort the HTTP request after a parallel stream timeout. I used the following piece of code:

HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();

HttpRequestBase request = ...
request.setParams(httpParameters);

HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutReal);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutReal);

request.setParams(httpParameters);
((DefaultHttpClient) client).setParams(httpParameters);

Thread t = new Thread(){
    public void run()
    {
        try
        {
            Thread.sleep(4000);
            request.abort();
            client.getConnectionManager().closeExpiredConnections();
            client.getConnectionManager().closeIdleConnections(4000,TimeUnit.MILLISECONDS);
            client.getConnectionManager().shutdown();
            Log.i("TEST SHUTDOWN","SHUT DOWN ALL CONNECTIONS");
                }
            catch (InterruptedException e)
            {
            }
        }
    };

try
{
    t.start();
    HttpResponse httpResponse = client.execute(request);
}
catch (Exception e)
{
    Log.i("TEST SHUTDOWN","EXCEPTION "+e);
}
finally
{
    t.interrupt();
}

      

But even if I can see from the logs that the request is aborted and the connection manager is disabled, the execution of the request is not interrupted / interrupted and no exception is thrown at the given timeout. The request always ends after 20 seconds.

Any idea why?

+3


source to share


4 answers


What you can probably see is that the DNS lookup is a timeout. When your HTTP client tries to establish a connection, the first thing it does is try to resolve the hostname of your URL to an IP address. That being said, it ignores your timeout settings (these timeout values ​​are only used when trying to actually make a socket connection). If you don't have a good internet connection, your DNS lookup will simply stop until it times out. Once this happens, your HTTP request will end immediately with UnknownHostException

.

Unfortunately, you have no control over the DNS timeout, so the only way to fix your problem is to first determine if your DNS resolution is working. You have to do this in a separate thread, and if you don't get a successful host resolution within a few seconds, you know your internet connection is not reliable and you don't even have to try to make an HTTP request.

So, you can try something like this:



HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();

HttpRequestBase request = ...
request.setParams(httpParameters);

HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutReal);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutReal);

request.setParams(httpParameters);
((DefaultHttpClient) client).setParams(httpParameters);

// The thread that is waiting to execute the HTTP request
final Thread waitingThread = Thread.currentThread();

Thread t = new Thread() {
    boolean running = true;
    public void run() {
        try {
            // Try to resolve the host name
            InetAddress addr = InetAddress.getByName (hostname);
            // Successful resolution, notify the waiting thread
            if (running) {
                // Signal the waiting thread that it can do the HTTP request now
                waitingThread.interrupt();
            }
        } catch (Exception e) {
            // Some problem, just ignore it
        }
    }
};

try {
    // Start name resolution
    t.start();
    // Sleep for as long as we are willing to wait for the DNS resolution
    Thread.sleep(4000);
    // If we slept the entire time without getting interrupted, the DNS resolution took too long
    //  so assume we have no connectivity.
    t.running = false; // We don't want to be interrupted anymore
    // Don't even bother trying the HTTP request now, we've used up all the time we have
} catch (InterruptedException ie) {
    // We got interrupted, so the DNS resolution must have been successful. Do the HTTP request now
    HttpResponse httpResponse = client.execute(request);
}

      

I am writing this code without trying it, so please forgive any typos or missing semicolons. You should get this idea.

+7


source


You can try using AndroidHttpClient instead of DefaultHttpClient. It has certain settings for Android.

Alternatively, you can try replacing the following line:

HttpParams httpParameters = client.getParams();

      



with the next line

HttpParams httpParameters = new BasicHttpParams();

      

I don't know if this is the correct answer, but I hope it helps.

+1


source


The 20 second part of your question rfc2616 indicates 5 redirects times 4000 milis = 20 seconds. The solution is to test the network connectivity before trying to access the network.

// check for network connection
        ConnectivityManager connMgr = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connMgr == null) {
            return false;  // I get a null here when there is no connection on my lg f6.
        }

        // check ok to process
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
        if (networkInfo == null || !networkInfo.isConnected()) {
            return false;
        }

       return true;

      

0


source


Ok I had a similar problem. This is what I did to solve it.

First, I create an instance of HttpParams:

HttpParams params = new BasicHttpParams();

      

Then I don't set the settings manually. Instead, I use a class HttpConnectionParams

for this. For example:

HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, httpTimeout * 1000);
HttpConnectionParams.setSoTimeout(params, httpTimeout * 1000);

      

Then I pass the generated parameters when I instantiate the html client:

HttpClient client = new DefaultHttpClient(params);

      

I am also using the Client Connection Manager, so I am passing it as the first parameter in the above call.

So the trick is to create the HttpClient by passing in the already configured parameters and then not iterating over them.

Hope this works for you.

EDIT: Have you tried blocking redirects? HttpClientParams.setRedirecting(params, setRedirecting);

0


source







All Articles