1

I got a very annoying problem now with my android development. I have a list which loading a bunch of content, each is an xml file with different address. Which means I need to sends bunch of http get request to server.

The problem if the request is less than roughly 180 times, I mean continues, very fast http request, the app just works fine. When the amount reach around 180, the connection to internet of the whole device will be lost. That means not only the app won't work, even the default browser or other apps which require internet will also not work.

This will recover after 1 minutes or two. But during this time there are no internet connection.

I do have set permissions in mifest file.

Here is my code for http connection:

public class HTTPService {


    private static String response;


    public  HTTPService() {
        response = null;
    }


    public static String httpGet(String requestURL) {

        //Reset response's value to null
        response = null;
        //DEBUG LOG
        Log.i("HTTPService", "Start GET request with URL " + requestURL);

        //this function will do http getting action and response checking at same time.
        //and assign proper information into the response string.
        executeRequest(new HttpGet(requestURL));

        Log.i("HTTPService", "GET request return with: " + response);

        return response;
    }

    public static String httpPost(String requestURL, String postString) throws Exception {

        //Assemble POST request
        HttpPost request = new HttpPost(requestURL);
        StringEntity input = new StringEntity(postString);
        input.setContentType(CommonCodes.CONTENT_TYPE);
        request.setEntity(input);

        //DEBUG LOG
        Log.i("HTTPService", "Start POST request with URL" + requestURL + ", and post content " + postString);

        executeRequest(request);

        return response;

    }

    public static void httpPut(String requestURL, String postString) throws Exception {

        //Assemble PUT request
        HttpPut request = new HttpPut(requestURL);
        StringEntity input = new StringEntity(postString);
        input.setContentType(CommonCodes.CONTENT_TYPE);
        request.setEntity(input);

        //DEBUG LOG
        Log.i("HTTPService", "Start PUT request with URL" + requestURL + ", and put content " + postString);

        executeRequest(request);

    }

    public static String httpDelete(String requestURL) {

        HttpDelete request = new HttpDelete(requestURL);
        //DEBUG LOG
        Log.i("HTTPService", "Start DELETE request with URL" + requestURL);
        executeRequest(request);
        return response;

    }


    public static void executeRequest(HttpUriRequest request) {

        //Check Internet Connection
        if (!CheckInternetConnection.checkInternetConnection()) {
            responseValidation(CommonCodes.NO_CONNECTION, 0);
        }




        HttpClient client = sslHttpClient();
        HttpResponse httpResponse;

        try {


            //*********PLACE WHERE ERROR HAPPENS IN ERROR LOG!******//
            httpResponse = client.execute(request);

            //Check if the request success. If it success, should return 200 as status code.
            if (httpResponse.getStatusLine().getStatusCode() != CommonCodes.HTTP_SUCCESS) {
                //DEBUG LOG
                Log.i("HTTPService", "Request failed with HTTP status code" + httpResponse.getStatusLine().getStatusCode());
                //Go through checker
                responseValidation(null, httpResponse.getStatusLine().getStatusCode());
            }

            //When request succeed, retrieve data.
            //HttpEntity entity = httpResponse.getEntity();

            //Convert stream data into String.
            if (!httpResponse.getEntity().equals(null)) {

                InputStream instream = httpResponse.getEntity().getContent();

                //Convert InputStream to String.
                response = convertStreamToString(instream).trim();

                //Close stream
                instream.close();
                httpResponse.getEntity().consumeContent();
            }

            //Go through checker
            responseValidation(response, httpResponse.getStatusLine().getStatusCode());

            client.getConnectionManager().shutdown();

        } catch (ClientProtocolException e) {
            Log.e("HTTPService: ", "HTTP Request With ClientProtocolException Detected");
            client.getConnectionManager().shutdown();
            e.printStackTrace();

        } catch (IOException e) {
            Log.e("HTTPService: ", "HTTP Request With IOException Detected");
            client.getConnectionManager().shutdown();
            e.printStackTrace();

        }

    }



    public static void  responseValidation (String response, int statusCode)
    {
        //Is this a HTTP Error?
        if (statusCode != CommonCodes.HTTP_SUCCESS) {
            response = CommonCodes.HTTP_FAIL;
        }
        //Is the response contains nothing?
        else if (response.equals(null) || response.equals("")) {
            response = CommonCodes.RESPONSE_EMPTY;
        }
        //Is there an internet connection?
        else if (response.equals(CommonCodes.NO_CONNECTION)){
            response = CommonCodes.NO_CONNECTION;
        }

    }


    public static HttpClient sslHttpClient() {
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);

            SSLSocketFactory sf = new SSLSocket(trustStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

            HttpParams params = new BasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory
                    .getSocketFactory(), 8080));
            registry.register(new Scheme("https", sf, 8443));


            ClientConnectionManager ccm = new ThreadSafeClientConnManager(
                    params, registry);


            return new DefaultHttpClient(ccm, params);
        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }

    private static String convertStreamToString(InputStream is) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }

The error message I got when the connection lost is this:

05-06 12:13:57.697  28670-28767/com.lai.android E/HTTPService:﹕ HTTP Request With IOException Detected
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ org.apache.http.conn.HttpHostConnectException: Connection to http://test.myworkspace.com:8080 refused
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:183)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at com.lai.android.services.http.HTTPService.executeRequest(HTTPService.java:138)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at com.lai.android.services.http.HTTPService.httpGet(HTTPService.java:73)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at com.lai.android.modules.watchlistgroup.WatchListActivity.getSingleVehicle(WatchListActivity.java:238)
05-06 12:13:57.697  28670-28767/com.lai.android W/System.err﹕ at com.lai.android.modules.watchlistgroup.WatchListActivity$InitWatchListActivity.doInBackground(WatchListActivity.java:144)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ at com.lai.android.modules.watchlistgroup.WatchListActivity$InitWatchListActivity.doInBackground(WatchListActivity.java:109)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ at android.os.AsyncTask$2.call(AsyncTask.java:287)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:137)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ at java.lang.Thread.run(Thread.java:856)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ Caused by: java.net.ConnectException: failed to connect to /192.168.48.95 (port 8080): connect failed: ENETUNREACH (Network is unreachable)
05-06 12:13:57.705  28670-28767/com.lai.android W/System.err﹕ at libcore.io.IoBridge.connect(IoBridge.java:114)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at java.net.Socket.connect(Socket.java:842)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:119)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:144)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ ... 17 more
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ Caused by: libcore.io.ErrnoException: connect failed: ENETUNREACH (Network is unreachable)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at libcore.io.Posix.connect(Native Method)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:85)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
05-06 12:13:57.713  28670-28767/com.lai.android W/System.err﹕ at libcore.io.IoBridge.connect(IoBridge.java:112)
05-06 12:13:57.721  28670-28767/com.lai.android W/System.err﹕ ... 22 more

Any advice will be welcome! I'm thinking if this is caused by running up of ports. But I don't know how to solve it. Thank you!

Arthur Wang
  • 3,118
  • 4
  • 21
  • 29

1 Answers1

3

Lucky....I solved it.

The problem is I have too many HTTP Clients instance, which used up all ports on the Phone.

Android have a max connection limit, and it takes time to release the ports which are been used. So if the requests are heavy and happens in very short time, the device just won't got enough time to release them.

The solution is instead of using new client every time, use only one client for all request.

Adding this to the code:

private static HttpClient client;


public static synchronized void createHttpClient() {
    if(client == null) {
        Log.i("HTTPService", "Create Client");
        client = sslHttpClient();
    }

}

Then call this constructor from beginning of the application.

Then replace everywhere where create new http client with the static client.

Problem solved, I will go for a beer.

Arthur Wang
  • 3,118
  • 4
  • 21
  • 29
  • +1 for helping yourself with a beer after helping yourself as well. accept your answer though for a self conclusion in style. – Kerem Jan 30 '15 at 00:07