2

I have recently refactored some of my networking code in my android app to use the Google recommended HTTPUrlConnection. Previously, I was using Apache's HTTPClient. I'm not sure if either of those things are relevant.

The other thing I have recently done to my networking code is use AsyncTask for the calls. Previously I was just doing work on the main thread (obviously bad) and so my application would appear to hang when fetching data. The thing is, since switching to AsyncTask, I have pretty regularly experienced timeout errors.

Why do I get this timeout error?

 java.net.ConnectException: failed to connect to <url> (port 80): connect failed: ETIMEDOUT (connection timed out)

Here is my AsyncTask that makes the network call.

private class PostToPHP extends AsyncTask<PostToPHP, Void, String>
{
    private String functionName;
    private ArrayList<NameValuePair> postKeyValuePairs;

    public PostToPHP(String function, ArrayList<NameValuePair> keyValuePairs)
    {
        functionName= function;
        postKeyValuePairs = keyValuePairs;
    }

    @Override
    protected void onPreExecute()
    {
        progressDialog = ProgressDialog.show(BaseActivity.getInstance(), "Loading", "Please wait...", true, false);
    }

    @Override
    protected String doInBackground(PostToPHP... params)
    {
        ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair(FUNCTION_NAME, functionName));
        for (int i = 0; i < postKeyValuePairs.size(); i++) {
            nameValuePairs.add(postKeyValuePairs.get(i));
        }

        try {
            URL url = new URL("www.myurl");
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setRequestProperty("Accept-Charset", iso-8859-1);
            OutputStream os = urlConnection.getOutputStream();
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, iso-8859-1));
            writer.write(getEncodedPostParameters(nameValuePairs, iso-8859-1));
            writer.close();
            os.close();

            InputStream is = urlConnection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, iso-8859-1));
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            is.close();
            urlConnection.disconnect();

            return sb.toString();
        }
        catch (UnknownHostException e) {
            // handle it

            return null;
        }
        catch (Exception e) {
            // this is where I'm always getting a timeout exception
            return null;
        }
    }

    @Override
    protected void onPostExecute(String result)
    {
        progressDialog.dismiss();
    }
}

EDIT: I thought this only occurred during one particular network call but I've now experienced it at various places.

EDIT 2: Looking at this again I found this and I think that's more of my problem. This didn't exist before I implemented Android AsyncTask for the network calls. I think that AsyncTask is somehow screwing up with threading and causing the timeouts.

Community
  • 1
  • 1
boltup_im_coding
  • 6,345
  • 6
  • 40
  • 52
  • Your request fails. Try adding a get request before write. Hope this hack would work. – Fahad Ishaque Mar 09 '13 at 21:22
  • The line that I don't make it past is actually `OutputStream os = urlConnection.getOutputStream();`. – boltup_im_coding Mar 09 '13 at 21:38
  • Did you tried simple get request to make sure that your connection is even made? Is the port 80 correct port? Your code seems fine. Please post complete logs. – Fahad Ishaque Mar 09 '13 at 21:53
  • Well thats the thing, this is intermittent. I use the above code many times. It errors just sometimes... As far as the port, how do I know what is the correct port? I don't set this, I just saw it in the error message. Perhaps my code is picking a port (80) sometimes that's not accepted by the server? – boltup_im_coding Mar 09 '13 at 22:01
  • Google didn't make a blanket recommendation for HttpUrlConnection, see the bottom of this article: http://android-developers.blogspot.com/2011/09/androids-http-clients.html. Older versions of Android (pre GB) had a few bugs with HttpUrlConnection, which version of Android are you seeing the problems on? – Charlie Collins Mar 10 '13 at 01:43
  • Yes, I saw that. I'm testing on two devices. 2.3.4 Droid X and 4.2.2 Nexus 7, so I don't believe those comments apply. – boltup_im_coding Mar 10 '13 at 03:38
  • @unexpected62 I am also got same issue on Android 4.4.2 xolo device.How to solve this issue using HTTPURLConnection(because apache client not recommended by google) – Ramprasad May 08 '14 at 04:45
  • @ramprasad i never figured this out. I know Google prefers HTTPURLConnection but the error was too frequent. – boltup_im_coding May 08 '14 at 04:49
  • Is it any official issue filed on android issue report – Ramprasad May 08 '14 at 05:20
  • @Ramprasad not that I have seen. – boltup_im_coding May 09 '14 at 16:34

2 Answers2

1

You could explicitly set the timeout for the HTTPUrlConnection:
urlConnection.setConnectionTimeout(aLongerTimeout)

Jeremy
  • 771
  • 6
  • 15
  • Actually you can't. You can only reduce the default connect timeout, not increase it. – user207421 Mar 10 '13 at 23:58
  • The docs say that you can set it to zero for an infinite timeout: http://docs.oracle.com/javase/1.5.0/docs/api/java/net/URLConnection.html#setConnectTimeout(int) – Jeremy Mar 11 '13 at 03:26
  • Yea, but that's not the underlying issue here. The issue was that for some reason this is occurring intermettently, and only with HttpUrlConnection, not Apache's HttpClient. I was wondering what is wrong (if any) with my code. I know its not a server problem as it works when I change back to Apache. – boltup_im_coding Mar 12 '13 at 04:36
  • @Jeremy The documentation is incorrect in this case. The default connect timeout varies by platform but it is of the order of a minute, and you cannot use this API to increase it, only to decrease it. If the default was infinite you would never see a 'connect timeout' exception except when this API had been used, and you do. – user207421 Mar 27 '13 at 06:17
1

I'm not very satisfied with this answer, but it seems to be working. I think there must be an issue with my code, or a bug in HTTPUrlConnection of some sort. I know Google said it had bugs in Froyo and lower, but I'm seeing oddities in 2.3.4 and 4.2 which I'm testing with. Essentially I replaced my code above with Apache's code and I'm not seeing the timeouts.

private static String post(ArrayList<NameValuePair> params){        
    HttpClient httpclient = new DefaultHttpClient();
    HttpPost httpreq = new HttpPost("www.url.com");
    httpreq.setEntity(new UrlEncodedFormEntity(params));
    HttpResponse response = httpclient.execute(httpreq);
    HttpEntity entity = response.getEntity();
    InputStream is = entity.getContent();

    BufferedReader reader = new BufferedReader(new InputStreamReader(is, NetworkConstants.HTTP_ACCEPTED_CHARSET), 8);
    StringBuilder sb = new StringBuilder();
    String line = null;
    while ((line = reader.readLine()) != null) {
        sb.append(line + "\n");
    }
    is.close();          

    return sb.toString();
}
boltup_im_coding
  • 6,345
  • 6
  • 40
  • 52