2

I have an application that connects to a server. I set a timeout, disconnected the device from internet and tried to execute the post request to see if the timeout was called, but the connection keeps waiting forever. This is my code:

private static final int TIMEOUT_OPS = 3000 ;
private HttpClient mHttpClient;

public String sendToken(String token) throws IOException, AuthenticationException {
    JSONArray jsonData = new JSONArray();
    jsonData.put(token);

    final HttpPost post = prepareJSONRequest(jsonData.toString(), SEND_TOKEN_METHOD);
    HttpClient httpClient = getConnection();
    Log.i(TAG, "Sending request");
    final HttpResponse resp;
    try{
        resp = httpClient.execute(post);
    }catch(Exception e){
        e.printStackTrace();
        return null;
    }
    Log.i(TAG, "Got response");
    ...
}

private HttpPost prepareJSONRequest(String rest_data, String method) throws AssertionError {
    AbstractHttpEntity entity = null;
    try {
        final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair(KEY_PARAM_METHOD, method));
        params.add(new BasicNameValuePair(KEY_PARAM_INPUT_TYPE, JSON));
        params.add(new BasicNameValuePair(KEY_PARAM_RESPONSE_TYPE, JSON));
        params.add(new BasicNameValuePair("rest_data", rest_data));
        entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
        final HttpPost post = new HttpPost(mServer);
        post.addHeader(entity.getContentType());
        post.setEntity(entity);
        return post;

    } catch (final UnsupportedEncodingException e) {
        // this should never happen.
        throw new AssertionError(e);
    }
}

private HttpClient getConnection() {
    if (mHttpClient == null) {
        // registers schemes for both http and https
        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
        HttpProtocolParams.setUseExpectContinue(params, false);
        HttpConnectionParams.setConnectionTimeout(params, TIMEOUT_OPS);
        HttpConnectionParams.setSoTimeout(params, TIMEOUT_OPS);
        ConnManagerParams.setTimeout(params, TIMEOUT_OPS);
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
        sslSocketFactory.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        if (!mNoCertValidation)
            registry.register(new Scheme("https", sslSocketFactory, 443));
        else
            registry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
        ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry);
        mHttpClient = new DefaultHttpClient(manager, params);

    }
    return mHttpClient;
}

If I execute this code, my log shows "Sending request", but doesn't print the exception or "Got response". Why doesn't it work?

PX Developer
  • 8,065
  • 7
  • 42
  • 66
  • Have you set permission for internet in Manifest file? – Martin Vandzura Sep 27 '12 at 18:12
  • If you have no Internet the DNS request will fail, but you cannot control the DNS timeout. Eventually you should get an UnknownHostException, but this may take several minutes. In this case the best thing to do is to start a timer in a separate thread at the same time you make the HTTP request. If the timer goes off before the HTTP request has finished, you can abort the HTTP request. – David Wasser Sep 27 '12 at 18:18
  • Thank you David, I'll do it like this. – PX Developer Sep 27 '12 at 19:04
  • Yeah, I always accept the helpful answers so other people with the same problem can know how to solve it =) – PX Developer Sep 28 '12 at 07:17

1 Answers1

5

If you have no Internet the DNS request will fail, but you cannot control the DNS timeout. Eventually you should get an UnknownHostException, but this may take several minutes. In this case the best thing to do is to start a timer in a separate thread at the same time you make the HTTP request. If the timer goes off before the HTTP request has finished, you can abort the HTTP request.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • Your explanation sounds reasonable. Another thing one could do is to listen for changes in network status like described in http://stackoverflow.com/questions/3307237/how-can-i-monitor-the-network-connection-status-in-android. – wojciii Oct 01 '12 at 04:00
  • 1
    @wojci true. However, My experience has shown that if you have spotty/bad connectivity that you often see connection timeouts and DNS timeouts, but you don't see a network status event change (because you theoritically have connectivity, it just doesn't work). Network status changes are useful/reliable for cases where the user enables/disables connectivity or you are in a situation where you really have no data connectivity at all. Just my personal experience. – David Wasser Oct 04 '12 at 08:59
  • This sounds as making sense but after trying it with a `Thread` and `Thread.sleep(time)` and also with a `Timer.schedule()` to call `HttpGet.abort()`, after this method no `IOException` was thrown and `execute()` followed its execution after circa 30 seconds. – AxeEffect Feb 20 '14 at 03:29