Question

This is a bit of a complicated question as I do not know the exact problem. The main issue is that it takes a very long to get a very small package of data from our REST server from our Android app. I will describe it in detail and hope you can help me.

Problem

Data retrieval is fast enough (+/- 100ms) when:

  • Connected with WiFi
  • Connected with HSDPA
  • Running on Android Emulator with network settings (delay and speed) set to GPRS

However, when I use a phone on a location with bad connection (3G instead of HSDPA) calling the services can take up to 4s (current timeout on the AsyncTask).

Android

This is the code used to communicate with the services:

 /**
 * Get json string from service
 *
 * @param urlString url of service
 * @return json result from service
 */
private String callService(String urlString) {
    InputStream in = null;
    HttpURLConnection c = null;
    Scanner s = null;
    String json = null;
    try {
        URL url = new URL(urlString);
        Log.i(getClass().getName() + ".callService()", "start calling service: " + url);
        long start = java.lang.System.currentTimeMillis();
        try {
            setAuthentication();
            c = (HttpURLConnection) url.openConnection();
            c.connect();
            in = new BufferedInputStream(c.getInputStream());
            s = new Scanner(in);
            s.useDelimiter("\\A");
            json = s.next();

        } catch (IOException e) {
            Log.e(getClass().getName() + ".callService()", "error: " + e.getMessage(), e);
        }
        Log.i(getClass().getName() + ".callService()", "complete calling service: (" + (System.currentTimeMillis() - start) + " ms) " + url);
        return json;
    } catch (Exception e) {
        Log.e(getClass().getName() + ".callService()", "error: " + e.getMessage(), e);
    } finally {
        if (s != null) {
            s.close();
        }
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                Log.e(getClass().getName() + ".callService()", "error: " + e.getMessage(), e);
            }
        }
        if (c != null) {
            c.disconnect();
        }
    }
    return json;
}

I have tried several ways to call this, but currently this is done using an AsyncTask:

    /**
 * Retrieve json from service
 *
 * @param url url of service
 * @return json
 */
public String getJsonFromServiceBasic(String url) {
        ServiceTask task = new ServiceTask();
        try {
            return task.execute(url).get(4000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            Log.e(getClass().toString() + " getJsonFromServiceBasic(" + url + ")", " interrupt exception: " + e.getMessage(), e);
        } catch (ExecutionException e) {
            Log.e(getClass().toString() + " getJsonFromServiceBasic(" + url + ")", " execution exception: " + e.getMessage(), e);
        } catch (TimeoutException e) {
            task.cancel(true);
            Log.e(getClass().toString() + " getJsonFromServiceBasic(" + url + ")", " timeout exception: " + e.getMessage(), e);
        } catch (Exception e) {
            Log.e(getClass().toString() + " getJsonFromServiceBasic(" + url + ")", " timeout exception: " + e.getMessage(), e);
        }
        return null;
}


/**
 * AsyncTask way of calling service
 */
class ServiceTask extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... urls) {
        String json = callService(urls[0]);
        return json;
    }
}

AndroidManifest.xml:

<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

Services

I do not think this is the issue, as it works fast enough with HSDPA, but I am not sure. Restlet services on tomcat7 behind a proxy. We're using a ChallengeAuthenticator for authentication.

Was it helpful?

Solution

I have solved this problem by switching to Apache's HttpClient. I am not sure why this is a solution as Google suggests using the HttpURLConnection, but for me this works.

Using this method instead of the callService method will solve my troubles with slow internet access.

private String callServiceClient(String urlString) {

    String json = null;

    HttpParams httpParams = new BasicHttpParams();
    int connection_Timeout = 5000;
    HttpConnectionParams.setConnectionTimeout(httpParams, connection_Timeout);
    HttpConnectionParams.setSoTimeout(httpParams, connection_Timeout);

    DefaultHttpClient httpClient = new DefaultHttpClient(httpParams);
    httpClient.getCredentialsProvider().setCredentials(new AuthScope(null, -1),
            new UsernamePasswordCredentials(user, password));

    HttpGet httpget = new HttpGet(urlString);

    // Execute the request
    HttpResponse response;
    try {
        response = httpClient.execute(httpget);
        // Examine the response status
        StatusLine responseCode = response.getStatusLine();
        Log.i(getClass() + ".callServiceClient()", "responsecode: " + responseCode);
        if (responseCode.getStatusCode() != HttpStatus.SC_OK) {
            return json;
        }

        // Get hold of the response entity
        HttpEntity entity = response.getEntity();
        // If the response does not enclose an entity, there is no need
        // to worry about connection release

        if (entity != null) {

            // A Simple JSON Response Read
            InputStream instream = entity.getContent();
            json = convertStreamToString(instream);
            // now you have the string representation of the HTML request
            instream.close();
        }
    } catch (ClientProtocolException e) {

    } catch (IOException e) {
        e.printStackTrace();
    }

    return json;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top