JSON parsing on 3g results in connection refused - android

I have this issue that has caused me to pound my head against the wall. I am writing a newspaper app that parses data in JSON from a database and displays it. The app works fine and passes data on WiFi and 4G, but chokes on 3G. Most of the time it takes between 30 seconds and 1 minute to grab data on 3G while only taking one to two seconds on WiFi. I often receive a warning message stating: HttpHostConnectException: Connection refused. I know the site works perfectly fine and is not causing issues because I can query fine on WiFi and 4G along with navigating from a desktop just fine with no problems. As another test, I borrowed my coworkers MiFi which is only on 3G in our area, and connected my device to it, and it passes data just fine although it is only 3G back to the Internet. So after looking at this, and trying to find a solution, I have come to the conclusion that maybe I am not doing something right on my end. To the best of my knowledge, everything is fine, but I am no expert. Any insight on this would be greatly appreciated.
Summary--
4G = Works
WiFI = Works
3G = Extremely slow
3G via WiFi(MiFi on 3G) =Works
public JSONObject makeHttpRequest(String url, String method, List params) {
// Making HTTP request
try {
if(method == "GET"){
// request method is GET
DefaultHttpClient httpClient = new DefaultHttpClient();
String paramString = URLEncodedUtils.format(params, "utf-8");
url += "?" + paramString;
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
System.out.println("---GET--- Now grabing GET DATA");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}

Is the 3G on my MiFi equally slow? Cause otherwise it sounds like you are saying that your process fails where the connection is slow.
You mention that 3G takes > 30s. Are you running on app engine? GAE has a hard limit on how long transactions can take - I believe that limit is 30s.
What if you added a delay on your server so that even a Wifi request takes as long as 3G tests are taking now - to verify that it is the time taken that is causing the failure.
Also, I think those 3G results sound rather poor. I don't know how much data you are retrieving but it really doesn't sound like it should take that long. So perhaps your 3G connection is simply a poor quality connection (and the MiFi perhaps is a better 3G connection).

Related

Google Maps Geocoding API V3 search ok with wifi but responses OVER_QUERY_LIMIT with data connection

My Google Maps activity searches for addresses with Google Maps Geocoding API V3.
I see that sometimes, even if I repeat the search multiple times in sequence, Google Maps response is OVER_QUERY_LIMIT when I'm connected with data connection.
It also happens on the first search after app's installation on a device.
When I'm connected with wifi it works perfectly.
Here's my code.
Search method:
public static JSONObject getAddressInfo(String sAddress) {
HttpGet httpGet = new HttpGet("http://maps.google.com/maps/api/geocode/json?address=" + sAddress + "&region=it&language=it&sensor=false");
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();
try {
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
} catch (ClientProtocolException e) {
} catch (IOException e) {
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject = new JSONObject(stringBuilder.toString());
Log.d("Google Geocoding Response", stringBuilder.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
Response management:
JSONObject jsonObject = Utils.getAddressInfo(Utils.strToUrl(inputName.getText().toString().trim()));
try {
String sStatus = jsonObject.getString("status");
if (sStatus.equals("OK")) {
lng = ((JSONArray)jsonObject.get("results")).getJSONObject(0).getJSONObject("geometry").getJSONObject("location").getDouble("lng");
lat = ((JSONArray)jsonObject.get("results")).getJSONObject(0).getJSONObject("geometry").getJSONObject("location").getDouble("lat");
bdlData.putDouble("lat", lat);
bdlData.putDouble("lng", lng);
bdlData.putFloat("dZoom", dZoom);
message.setData(bdlData);
mapHandler.sendMessage(message);
} else if (sStatus.equals("ZERO_RESULTS")) {
runMsgOnUIThread("Nessun risultato trovato.");
} else if (sStatus.equals("OVER_QUERY_LIMIT")) {
runMsgOnUIThread("Impossibile effettuare la ricerca al momento. Riprovare fra qualche secondo.");
} else if (sStatus.equals("REQUEST_DENIED")) {
runMsgOnUIThread("Richiesta non accettata. Riprovare.");
} else if (sStatus.equals("INVALID_REQUEST")) {
runMsgOnUIThread("Indirizzo non esistente.");
} else if (sStatus.equals("UNKNOWN_ERROR")) {
runMsgOnUIThread("Impossibile effettuare la ricerca al momento. Riprovare.");
}
} catch (JSONException e) {
e.printStackTrace();
}
Your problem most probably resides in your mobile operator. The vast majority of operators use a technique called NAT overloading and assign the same external IP to a number of devices. If your operator assigns a very large number of devices to a single IP and a number of them uses similar services, everyone will have a problem, as all requests will appear to stem from the same IP.
Your success with the 10*200ms requeries seems to be connected with the expiration of the OVER_QUERY_LIMIT flag from the server-side, as it is implied in this(Usage Limits for Google Maps API Web Services) document, which suggests that upon receiving this status, you should requery after 2secs to see if you exceeded your daily usage or you sent too many requests.
This does not occur through wifi as your phone has its own, more-or-less unique IP.
I found a workaround that often (not always) solves the problem: requerying Google every 200 ms if I get OVER_QUERY_LIMIT, for a maximum of 10 times.

Geocoder - Service not available on Android 2.3

I know this question has been asked several times, but still I'm getting this error.
Tried both on emulator and actual device, triend chahging emulator's target to Google API and also changed the target build of the project to Google API's
Need help on these :( Thanks!
I hope you solved it by now. As you said, there are many thread to it. After studying all the threads the answer I got was that Geocoder doesn't always return a value. You can try to send a request 3 times in a for loop. I might be able to return atleast once. If not then, their might be a connection issue or can be other issues like server does not reply to your request.
I had a while loop as well but I used to try it maximum for 10 times. Sometimes, it never returned anything even if it was connected to internet. Then, I used this much more reliable way to get the address everytime:
I used to get the latitude and longitude and then request google servers, to reply with a JSON object containing various information about the location co-ordinates. This way of getting address string does not require Geocoder. Here is the function:
public JSONObject getLocationInfo() {
HttpGet httpGet = new HttpGet("http://maps.google.com/maps/api/geocode/json?latlng="+lat+","+lng+"&sensor=true");
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();
try {
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
} catch (ClientProtocolException e) {
} catch (IOException e) {
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject = new JSONObject(stringBuilder.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
I called it as follows:
JSONObject ret = getLocationInfo();
JSONObject location;
String location_string;
try {
location = ret.getJSONArray("results").getJSONObject(0);
location_string = location.getString("formatted_address");
Log.d("test", "formattted address:" + location_string);
} catch (JSONException e1) {
e1.printStackTrace();
}
Hope this helps. I was also tired of relying on Geocoder. This worked for me. Though it might be just a little slower than geocoder. For testing its functionality, you can just place in the URL with the lat and longitude coordinates you are having. Try to see the returned JSON object in a web browser. You'll see how you can extract the address string. Try and read these threads as well:
Geocoder doesn't always return a value and geocoder.getFromLocationName returns only null

Memory leak with Android app?

I have a simple Android app that reads some JSON data from a php file on my local server. It's very simple and up until about an hour ago it was working fine. However, after a little break (I didn't even turn my PC off), it's suddenly struggling with what seems like a memory leak, although I'm no expert on the subject.
I'm not sure why all of a sudden this is happening, as I didn't change any code. But when I run the app my logcat slowly starts to fill with messages like this:
"GC_CONCURRENT freed, 910K, 53% free 3167K/6727K....."
The app eventually runs, but only after about 1-2 minutes of waiting. Anyway, I was wondering if someone could check my code or advise me what maybe causing this to happen.
public static JSONArray getJSONfromURL(String url) {
// initialize
InputStream is = null;
JSONArray jArray = null;
String result = "";
// http post
try {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
Log.e("log_tag", "Error in http connection " + e.toString());
}
// convert response to string
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "utf-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
Log.e("log_tag", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jArray = new JSONArray(result);
} catch (JSONException e) {
Log.e("log_tag", "Error parsing data " + e.toString());
}
return jArray;
}
The JSON data isn't very large at all.
Thanks for any advice.
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "utf-8"), 8);
You've allocated a buffer size of 8 bytes. That is very small. Unless you really know what you're doing, just use the default size with the alternative single-argument constructor:
public BufferedReader(Reader in)
Well I changed the 'While' loop to this and performance increased dramatically:
int len;
char[] chars = new char[4*1024];
while((len = reader.read(chars))>=0) {
sb.append(chars, 0, len);
}
It's still slower than I'd like, but at least I'm heading in the right direction. I'm going to work on it some more. Thanks everyone.

Android HttpURLConnection throwing EOFException

Here's the question in simplest way.
I create a HTTPS connection to my server through proxy using HttpUrlConnection Object.
My proxy closes the connection but my code still tries to reuse the same connection. And so I get EOFException.
How do I handle such cases?
I'd recommend disabling the http.keepalive system property. The performance section of the documentation indicates that socket connections will be reused when possible. It sounds like it is trying to reuse the connection, but the proxy has already closed it. On this post, Darrell also indicates that changing the system property solved his problem.
System.setProperty("http.keepAlive", "false");
Turns out they've fixed this issue in Android on Jan 8th [1]. The fix basically marks the old connection as recycled and internally retries the request.
To fix this for now, I would suggest retrying requests if an EOFException is encountered with a retry limit to prevent stackoverlows.
https://android.googlesource.com/platform/libcore/+/19aa40c81c48ff98ccc7272f2a3c41479b806376
I had this problem with normal HTTP connections as well. The first request went OK, the second failed with an EOFException.
Eventuelly I fixed it by removing...
urlConnection.setChunkedStreamingMode(0);
...from the HttpUrlConnection.
I could be that the webserver I'm calling can't handle chuncked data well. Don't know.
If you don't want to reuse the connection then release it.
finally {
urlConnection.disconnect();
}
You can use this method to pick data from server then you convert the inputs trim to string then you can parse for further use.`
public static InputStream getUrlData(final String url)
throws URISyntaxException, ClientProtocolException, IOException {
final DefaultHttpClient client = new DefaultHttpClient();
final HttpGet method = new HttpGet(new URI(url));
final HttpResponse res = client.execute(method);
return res.getEntity().getContent();
}
Maybe httpClient "has more bugs" and is deprecated, but this problem with JellyBean is a showstopper. I am using Ksoap2 so I tried all the suggested answers that I could.
System.setProperty("http.keepAlive", "false");
httpTransportSE.getServiceConnection().setRequestProperty("Connection", "close");
httpTransportSE.getServiceConnection().disconnect();
Nothing worked - my solution was to rollback the version of Ksoap2 I'm using from 3.1.1 to 2.6.5. Using 2.6.5 the problem is substantially reduced. Still testing but maybe even solved.
I found that retrying the connection fixes the issue as seen here: https://stackoverflow.com/a/20302767/2520390
Make sure you close off the connection before your recursive call.
Also, I added the following to the connection to close the connection, though I'm not sure if it helps:
if (retries > 0) {
connection.setRequestProperty("Connection", "close");
}
You shouldn't be attempting to reuse the same HttpURLConnection instance. The docs in the very bottom line of the "Class Overview" say
Each instance of HttpURLConnection may be used for one
request/response pair.
Keep-Alive connections work at a different level, see the disconnect docs:
http://developer.android.com/reference/java/net/HttpURLConnection.html#disconnect()
Unlike other Java implementations, this will not necessarily close
socket connections that can be reused. You can disable all connection
reuse by setting the http.keepAlive system property to false before
issuing any HTTP requests.
So you should always use a fresh HttpURLConnection and let the socket pool handle re-use.
There were apparently bugs with keep-alive connections pre-Froyo (2.2) so it is recommended to disable keep-alive on those old devices.
In my case the EOFException was caused by my server not sending a full response, see the details here: https://stackoverflow.com/a/27845172/2335025
You shouldn't be attempting to reuse the same HttpURLConnection instance. The docs in the very bottom line of the "Class Overview" say
Each instance of HttpURLConnection may be used for one
request/response pair.
Keep-Alive connections work at a different level, see the disconnect docs:
http://developer.android.com/reference/java/net/HttpURLConnection.html#disconnect()
Unlike other Java implementations, this will not necessarily close
socket connections that can be reused. You can disable all connection
reuse by setting the http.keepAlive system property to false before
issuing any HTTP requests.
So you should always use a fresh HttpURLConnection and let the socket pool handle re-use. There are perhaps issues if it tries to reuse a socket that has been closed by the server, which the answers to this question deal with: Android HttpUrlConnection EOFException
There were apparently bugs with keep-alive connections pre-Froyo (2.2) so it is recommended to disable keep-alive on those old devices.
In my case the EOFException was caused by my server not sending a full response, see the details here: https://stackoverflow.com/a/27845939/2335025
if (Build.VERSION.SDK != null
&& Build.VERSION.SDK_INT > 13) {
con.setRequestProperty("Connection", "close");
}
Try this code:`
Httppost method:
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT_MILLISEC);
HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT_MILLISEC);
HttpClient client = new DefaultHttpClient(httpParams);
HttpPost request = new HttpPost("put_url");
request.setHeader("Content-Type", "application/xml");
String file = resourceXml();
StringEntity se = null;
try {
se = new StringEntity(file);
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
se.setContentEncoding("UTF-8");
se.setContentType("application/xml");
request.setEntity(se);
HttpResponse response = null;
try {
response = client.execute(request);
} catch (ClientProtocolException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
HttpEntity entity = response.getEntity();
InputStream is = null;
try {
is = entity.getContent();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String _response = convertStreamToString(is);
Log.i(TAG, "Response:" + _response);
// Check if server response is valid code
int res_code = response.getStatusLine().getStatusCode();
Log.i(TAG, "status_code" + res_code);
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
`
to convert stream to string:`
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is),
8192);
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();
}`

How to improve my Rest Calls on Android?

I am making an app for Android. I like to make the rest calls as quick as possible. When I get my results as XML it takes 5 seconds (!) to get a simple xml like this:
<souvenirs>
<souvenir>
<id>1</id>
<name>Example 1</name>
<rating>3.4</rating>
<photourl>/images/example.jpg</photourl>
<price>3.50</price>
</souvenir>
<souvenir>
<id>2</id>
<name>Example 2</name>
<rating>2.4</rating>
<photourl>/images/example.jpg</photourl>
<price>8.50</price>
</souvenir>
</souvenirs>
So I tried it with JSON. But that takes also about 5 seconds to retrieve.
I load the XML in android with the following code:
URL url = new URL("http://example.nu?method=getAllSouvenirs");
URLConnection conn = url.openConnection();
long t=System.currentTimeMillis();
InputStream ins = conn.getInputStream();
Log.d("info", String.valueOf((System.currentTimeMillis()-t)));
The log says it takes about 5000 ms to get the inputstream.. Is there any way to speed this up? does anybody knows which technique the Android Market uses? This loads way faster than my app..
Thanks in advance! :)
When you try to get the data "manually" - via browser or via other means (wget, curl) how long does it take there.
On Android you also should take the mobile network into consideration that is usually significantly slower than for a desktop computer. Also latencies are bigger.
To me this sounds a lot like issues in the backend (e.g. trying to resolve the IP of the client and thus taking lots of time).
use Apache HttpClient instead of URLConnection:
Apache http client or URLConnection
EDIT(2012-02-07): no longer true on newer android platform please read: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
Maybe that is how it is implemented and you can't do nothing. That is my guess.
My opinion is to do all connection based stuff on your own thread (to put in in background) and in foreground (main UI thread) entertain user. :)
I have played a little bit around this and it works fast enough for me... Here is my code:
private static HttpResponse doPost(String url, JSONStringer json) {
try {
HttpPost request = new HttpPost(url);
StringEntity entity;
entity = new StringEntity(json.toString());
entity.setContentType("application/json;charset=UTF-8");
entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json;charset=UTF-8"));
request.setEntity(entity);
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
return response;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
And somewhere else I call that method like:
HttpResponse httpResponse = doPost(url, json);
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"));
It works fine for me...

Categories

Resources