4

I am using the class HttpUrlConnection for requesting JSON responses

I realized that no matter if I set or not

System.setProperty("http.keepAlive", "false");

The first response is always going to take longer, while the next responses are very quick, with and without keepAlive. I am not even using SSL.

Notice that, my app doesn't need to perform any authentication with the server, so there isn't any startup call to the webservices. The first request I make to the webservices is actually the very first.

I am also verifying server-side with "netstat", that by setting keepAlive false on the Android client the connections disappear straight away, while without specifying keepAlive false they keep staying as "ESTABLISHED".

How can you explain that subsequent responses are quicker even if the connection doesn't persist?

ANDROID CODE:

line 1) URL url = new URL(stringUrl);
line 2) HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
line 3) InputStream instream = new BufferedInputStream(urlConnection.getInputStream());

Until line 2 everything always gets executed very quickly, either with keepAlive or not. Line 3 in the first request takes around 3 seconds, while in all subsequent always less than 1 second. Each request is about 0.5KB gzipped.

SYSTEM:

  • I am testing using a Nexus 5, connected via 3G
  • My webservices are written in Go, running on a CentOS 6.4 linux server
  • I am using standard tcp v4

UPDATE:

For the moment I have decided to use a trick: when the fragment is resuming, I make a HTTP HEAD request to the server. In this way all subsequent calls in the next 10 seconds are very quick. If the user waits more than 10 seconds then the first one will be slow, and the next ones will be quick again. This is all happening without using KeepAlive.

It's a really big mistery now. It looks like there is some kind of "awake" period which lasts for about 10 seconds. I don't think there is anything strange on my code which can result on that. Also because everything seems to happen during the line 3 I reported above.

SOLVED! thanks to Mark Allison!

Here is a very clear explanation: http://developer.android.com/training/efficient-downloads/efficient-network-access.html

Also, everything can easily be monitored using Android DDMS's Network Statistics. If you wait some seconds (let's say 20) from last request, you can see that it takes 2 seconds to transmit a new request.

Daniele B
  • 19,801
  • 29
  • 115
  • 173
  • is this on a cellular network or wifi? – edthethird Mar 19 '14 at 22:15
  • I've never noticed this and I've done A LOT of networking on Android. Are you sure this isn't an artificat of the set up/tear down from not reusing objects, or otherwise generated by your code and not the networking specifically? – Nathaniel D. Waggoner Mar 19 '14 at 22:21
  • Also if you have code you can show us we might be able to trouble shoot it. As this question stands I'm not sure it's really answerable. – Nathaniel D. Waggoner Mar 19 '14 at 22:22
  • what do you mean with an "artificat of the set up/tear down from not reusing objects" ? – Daniele B Mar 19 '14 at 22:22
  • So the way I see it there are two places you could be experieincing slow down (not including network fluctations): 1) IN the android code you're just being inefficient. This could be in the process of setting up your network requests, creating objects, serializing data or any other number of things. 2) On the server there might be some issue with the way you handle responses. I'm not a server expert so I can't really weigh in here. Again though I don't actually think this is an issue in the HttpUrlConnection or any of the android networking code for that matter. – Nathaniel D. Waggoner Mar 19 '14 at 22:24
  • @NathanielWaggoner, basically you are saying it can't be a communication problem but only an issue either on the client side or the server side... it's weird though. The same issue happened by using Android's Apache HttpClient. On the server side I can verify the first request arrives with some delay comparing to the next ones. – Daniele B Mar 19 '14 at 22:31
  • @NathanielWaggoner, I have added some code and a small paragraph below – Daniele B Mar 19 '14 at 22:57
  • This has to be in the setup, connections just don't work like that. Are you sure the first signal is going out when you think it is? – zgc7009 Mar 19 '14 at 23:11
  • @zgc7009, I don't get your statement. What do you mean this has to be in the setup? as I explained in the question, what takes all the time is line 3. I also tried to remove BufferedInputStream, but it doesn't help. The code I presented is inside an Async Task. – Daniele B Mar 19 '14 at 23:21
  • I don't see anything major there - but I also only see three lines of code. That's still not really enough code to know what's going on here. – Nathaniel D. Waggoner Mar 20 '14 at 15:17
  • Have you tried switing to your WiFi connection and running and comparing the timing results? It might be an issue with the 3g network. – Nathaniel D. Waggoner Mar 20 '14 at 15:17
  • have a look at the answer I accepted and also this link http://developer.android.com/training/efficient-downloads/efficient-network-access.html – Daniele B Mar 20 '14 at 16:14

3 Answers3

3

I suspect that the lag that you are seeing is simply down to the cellular radio transitioning from either low power or idle state to full power (which can take over 2 seconds).

Check out Reto Meier's excellent DevBytes series on Efficient Data Transfer for an in-depth explanation of what's going on.

Mark Allison
  • 21,839
  • 8
  • 47
  • 46
  • Thanks Mark, you spotted the solution! I will award you the bounty as soon as it becomes available tomorrow. I also report the full article from the Android website: http://developer.android.com/training/efficient-downloads/efficient-network-access.html – Daniele B Mar 20 '14 at 16:13
0
  1. The first request cannot leverage a keep-alive obviously, because thankfully Android doesn't keep the connections alive for minutes or hours. Only subsequent requests can reuse keep-alive connections and only after a short period of time.

  2. It's natural that you have to wait in line 3. Before something like conn.getResponseCode() or conn.getInputStream() the HttpURLConnection is in CREATED state. There is no network activity until it's getting in CONNECTED state. Buffered* shouldn't make any difference here.

  3. I've observed long delays when using SSL and there was a time-shift between server and device. This happens very often when using an emulator which is not cold-booted. For that I've a small script running before test. It's important that PC and emulator are in the same time-zone, otherwise it's very contra-productive: (see below, because it's hard to show the command inline).

  4. I can imagine that Android saves battery in putting 3G into sleep mode when there is no activity. This is just speculation, but you could make a test by creating some other network activity with other apps (browser, twitter, ...) and then see whether your app needs the same long "think time" until first connection.

  5. There are other good options for losing time: DNS resolution, Server-side "sleep" (e.g. a virtual machine loading "memory" from disk).

The command to set time of Android emulator:

adb -e shell date -s `date +"%Y%m%d.%H%M%S"`

Edit

To further analyze the problem, you could run tcpdump on your server. Here is tutorial in case you don't know it well. Store the dumps to files (pcap) and then you can view them with wireshark. Depending on the traffic on your CentOS server you have to set some filters so you only record the traffic from your Android device. I hope that this gives some insight to the problem.

To exclude your server from being the bad guy, you could create a small script with curl commands doing the equivalent as your app.

You could create a super-tiny service without database or other i/o dependencies and measure the performance. I don't know "Go", but the best thing would be a static JSON file delivered by Apache or nginx. If you only have Go, then take something like /ping -> { echo "pong" }. Please tell us your measurements and observations.

hgoebl
  • 12,637
  • 9
  • 49
  • 72
  • Thanks hgoebl for your answer! 1) the weird thing is that this is happening evening without keepAlive 2) thanks for confirming that buffered stream shouldn't make too much difference here 3) I am actually not using SSL 4) I guess there might be some 3G sleep mechanism in Android. The test you suggest makes sense. Thanks 5) At first when you mentioned DNS resolution I thought that's the one :-) but it looks like DNS caching in Android is at least 10 minutes by default. So, it can't be something happening every few seconds. – Daniele B Mar 20 '14 at 12:10
  • Can you please describe your topology? Devices used, server-software run, name-server, operating systems, tcp v4 and/or v6, etc. For better readability please edit your question. – hgoebl Mar 20 '14 at 13:24
  • Thanks, I have just added a paragraph to my question – Daniele B Mar 20 '14 at 13:30
  • hgoebl, I am wondering if this delay is actually normal, maybe simply due to the device waking up the required radio component. Unlike most apps, my app doesn't need to do any startup authentication with the server, so the first request I make to the webservices is actually the very first. – Daniele B Mar 20 '14 at 14:51
  • have a look at the answer I accepted and also this link http://developer.android.com/training/efficient-downloads/efficient-network-access.html – Daniele B Mar 20 '14 at 16:15
-1

Instead of using so many classes I suggest you use this library

you can have a look at here

http://loopj.com/android-async-http/

your code will become very very less , instead of declaring so many classes writing bulk of code , you can just use 4 lines of code

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
@Override
public void onSuccess(String response) {
System.out.println(response);
   }
});

It is very efficient in geting the response very quickly(1 or 2 secs including parsing).

I hope this will help you out. :)

Udit Kapahi
  • 2,277
  • 1
  • 27
  • 25
  • 2
    `Instead of using so many classes I suggest you use this library` this is not the problem ... now the classes are in library ... there is no differences ... well there is 1 ... loopj is using apache http client and he is using HttpURLConnection which is preffered on android API > 9 http://android-developers.blogspot.com/2011/09/androids-http-clients.html – Selvin Mar 19 '14 at 23:17