API call far faster on iOs and browser than on android - android

I have a trouble with my HttpsConnection on android.
First of all, no it is not a duplicate. I try almost all the solutions on SO, like changing the keep-alive option or the timeout ( and some of them indeed optimized a part of my code a little bit ) but it is still 5 to 10 times ( probably more ) slower on android than on iOS.
Sending a request to my server takes several seconds on android while it's almost instant on iOS and from a browser. I am sure that the server is not in cause. But it seems that getting the inputstream is terribly slow!
This line:
in=conn.getInputStream();
is the most delaying one, taking several seconds by itself.
My aim is to get a JSON from my server. My code is supposed to be technically as optimized as possible ( and it can probably help some people with HttpsConnection on the same time ):
protected String getContentUrl(String apiURL)
{
StringBuilder builder = new StringBuilder();
String line=null;
String result="";
HttpsURLConnection conn= null;
InputStream in= null;
try {
URL url;
// get URL content
url = new URL(apiURL);
System.setProperty("http.keepAlive", "false");
trustAllHosts();
conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(DO_NOT_VERIFY);
conn.setRequestMethod("GET");
conn.setRequestProperty(MainActivity.API_TOKEN, MainActivity.ENCRYPTED_TOKEN);
conn.setRequestProperty("Connection", "close");
conn.setConnectTimeout(1000);
in=conn.getInputStream();
// open the stream and put it into BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(in));
while ((line=br.readLine())!= null) {
builder.append(line);
}
result=builder.toString();
//System.out.print(result);
br.close();
} catch (MalformedURLException e) {
result=null;
} catch (IOException e) {
result=null;
} catch (Exception e) {
result=null;
}
finally {
try {
in.close();
}catch(Exception e){}
try {
conn.disconnect();
}catch(Exception e){}
return result;
}
}
However, it keeps taking several seconds.
So I would like to know: is there a way to improve the speed of this API call? The problem is not the server or the JSON parsing but for sure the function above. Thanks a lot.

Related

HttpURLConnection getInputStream() not reading anything

I'm following an example of using the Reddit API in an Android app. I'm using Android Studio and Java. I have a link which returns a JSON object on a GET request (let's say http://www.reddit.com/r/dragonforce/.json), and the tutorial has this piece of code:
public static HttpURLConnection getConnection(String url){
System.out.println("URL: "+url);
HttpURLConnection hcon = null;
try {
hcon=(HttpURLConnection) new URL(url).openConnection();
hcon.setReadTimeout(30000); // Timeout at 30 seconds
hcon.setRequestProperty("User-Agent", "Alien V1.0");
} catch (MalformedURLException e) {
Log.e("getConnection()",
"Invalid URL: "+e.toString());
} catch (IOException e) {
Log.e("getConnection()",
"Could not connect: "+e.toString());
}
return hcon;
}
and
public static String readContents(String url){
HttpURLConnection hcon=getConnection(url);
if(hcon==null) return null;
try{
StringBuffer sb=new StringBuffer(8192);
String tmp="";
BufferedReader br=new BufferedReader(
new InputStreamReader(
hcon.getInputStream()
)
);
tmp = br.readLine();
while(tmp !=null) {
sb.append(tmp).append("\n");
tmp = br.readLine();
}
br.close();
return sb.toString();
}catch(IOException e){
Log.d("READ FAILED", e.toString());
return null;
}
}
I separated the tmp assignment for debug purposes. The problem is that nothing is read from the inputStream, and it returns an empty buffer to the JSONObject parser, resulting in JSONException end of input at character 0 of. I have user-permission in the Manifest for INTERNET, and the syntax for reading from the URL seems to be backed up by other sources on the internet, but it still seems something is amiss. Any help would be appreciated.
For anyone who is reading this down the line, the problem was that the URL in the tutorial was using HTTP instead of HTTPS, leading to a redirect response code and wasn't returning anything.

Android: how can I make an HTTP HEAD request?

I would like to make a simple HTTP HEAD request, without keep-alive.
How can I do that in Android?
using HttpClient:
As njzk2 suggested, with HttpClient() it's very straightforward:
HttpResponse response = new HttpClient().execute(new HttpHead(myUrl));
However there is a problem with not being able to close the connection. Usually on the HttpClient, you would get the entity using:
HttpEntity entity = response.getEntity();
and then you would get the input stream from the entity
InputStream instream = entity.getContent();
...
instream.close();
and by closing the input stream, the connection would close.
However, in the case of a HEAD request, the entity appears to be null (possibly because HEAD requests don't return the body in the response), so the input stream cannot be fetched and closed and the connection doesn't close either.
In the last edit to his answer, njzk2 is suggesting to use AndroidHttpClient, which is a more recent implementation (API 8) of HttpClient and it actually has a close() method. I haven't used it but I guess it will work fine. However, as the Android development team suggests, the HttpUrlConnection should be the preferred Android client to use.
using HttpUrlConnection:
Actually it seems quite easy to make HEAD requests using HttpUrlConnection and make sure that the connection closes:
HttpURLConnection urlConnection = null;
System.setProperty("http.keepAlive", "false");
try {
URL url = new URL(stringUrl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("HEAD");
urlConnection.getInputStream().close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
Trivially :
HttpResponse response = new AndroidHttpClient().execute(new HttpHead(myUrl));
Typically you'll use the same AndroidHttpClient for several connections, then call close on it.
For ordinary Java and Android
I am using some standard Java code to test the existence of a resource and in the same time to check whether a resource has been changed, provided the parameter if_modified_since is non-zero.
URL url = new URL(adr);
try {
URLConnection con = url.openConnection();
con.setIfModifiedSince(if_modified_since);
if (con instanceof HttpURLConnection) {
/* Workaround for https://code.google.com/p/android/issues/detail?id=61013 */
con.addRequestProperty("Accept-Encoding", "identity");
((HttpURLConnection) con).setRequestMethod("HEAD");
int response = ((HttpURLConnection) con).getResponseCode();
if (response == HttpURLConnection.HTTP_UNAVAILABLE)
return false;
if (response == HttpURLConnection.HTTP_NOT_MODIFIED)
return false;
}
if (if_modified_since != 0) {
long modified = OpenOpts.getLastModified(con);
if (modified != 0 && if_modified_since >= modified)
return false;
}
InputStream in = con.getInputStream();
in.close();
return true;
} catch (FileNotFoundException x) {
return false;
} catch (UnknownHostException x) {
return false;
} catch (SocketException x) {
return false;
}
Interestingly the code needs a con.getInputStream() and I don't get some errors here. But I needed some helper code, to also cater for URIs that point to JARs. The helper code is:
private static long getLastModified(URLConnection con)
throws IOException {
if (con instanceof JarURLConnection) {
return ((JarURLConnection) con).getJarEntry().getTime();
} else {
return con.getLastModified();
}
}
The code can be further optimized by some specialization if the
URI is schema file: , one can then directly do File.exists() and File.getLastModified().
We do not throw a ServiceUnvailable exception here, we basically assume that the outer code would catch an IOException and then assume a false
result of the getHead().

Android: Quick web requests

For my application I need to have the latest data from an webpage that is hosted on a server on my local network.
So I request the latest page with a HTTP GET and when the data is received, I send another request.
With my current implementation I reach around the 100 - 120 ms per request. Is there a possibility to make this quicker because it's the same url that is requested.
For example keep the connection open to the page and grep the latest data without setting up a new connection?
This page is around the 900-1100 bytes.
HTTP get code:
public static String makeHttpGetRequest(String stringUrl) {
try {
URL url = new URL(stringUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setReadTimeout(300);
con.setConnectTimeout(300);
con.setDoOutput(false);
con.setDoInput(true);
con.setChunkedStreamingMode(0);
con.setRequestMethod("GET");
return readStream(con.getInputStream());
} catch (IOException e) {
Log.e(TAG, "IOException when setting up connection: " + e.getMessage());
}
return null;
}
Reading inputstream
private static String readStream(InputStream in) {
BufferedReader reader = null;
StringBuilder total = new StringBuilder();
try {
String line = "";
reader = new BufferedReader(new InputStreamReader(in));
while ((line = reader.readLine()) != null) {
total.append(line);
}
} catch (IOException e) {
Log.e(TAG, "IOException when reading InputStream: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return total.toString();
}
As I know there isn't an implementation like you are asking for. I've been dealing a lot with http requests and the best thing you can do is your code. There is another thing which need some attention...your connection maybe slow and depending on that connection time can be more or in some cases which I've been dealing a lot the connection's timeout isn't enough big, but that's server problem.
In my opinion you should use what you have now.

Do I need to call HttpURLConnection.disconnect after finish using it

The following code basically works as expected. However, to be paranoid, I was wondering, to avoid resource leakage,
Do I need to call HttpURLConnection.disconnect, after finish its usage?
Do I need to call InputStream.close?
Do I need to call InputStreamReader.close?
Do I need to have the following 2 line of code : httpUrlConnection.setDoInput(true) and httpUrlConnection.setDoOutput(false), just after the construction of httpUrlConnection?
The reason I ask so, is most of the examples I saw do not do such cleanup. http://www.exampledepot.com/egs/java.net/post.html and http://www.vogella.com/articles/AndroidNetworking/article.html. I just want to make sure those examples are correct as well.
public static String getResponseBodyAsString(String request) {
BufferedReader bufferedReader = null;
try {
URL url = new URL(request);
HttpURLConnection httpUrlConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = httpUrlConnection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
int charRead = 0;
char[] buffer = new char[1024];
StringBuffer stringBuffer = new StringBuffer();
while ((charRead = bufferedReader.read(buffer)) > 0) {
stringBuffer.append(buffer, 0, charRead);
}
return stringBuffer.toString();
} catch (MalformedURLException e) {
Log.e(TAG, "", e);
} catch (IOException e) {
Log.e(TAG, "", e);
} finally {
close(bufferedReader);
}
return null;
}
private static void close(Reader reader) {
if (reader != null) {
try {
reader.close();
} catch (IOException exp) {
Log.e(TAG, "", exp);
}
}
}
Yes you need to close the inputstream first and close httpconnection next. As per javadoc.
Each HttpURLConnection instance is used to make a single request but the underlying network connection to the HTTP server may be transparently shared by other instances. Calling the close() methods on the InputStream or OutputStream of an HttpURLConnection after a request may free network resources associated with this instance but has no effect on any shared persistent connection. Calling the disconnect() method may close the underlying socket if a persistent connection is otherwise idle at that time.
Next two questions answer depends on purpose of your connection. Read this link for more details.
I believe the requirement for calling setDoInput() or setDoOutput() is to make sure they are called before anything is written to or read from a stream on the connection. Beyond that, I'm not sure it matters when those methods are called.

Timeout when downloading a string

I am using the following two functions to download a string from a server. I am also logging the time it takes to download the text, both as seen by the client and also as seen by the server. The downloaded string is never the same.
The server time is only few milliseconds but the time seen by the client is on average 100 milliseconds depending on the wifi signal. Occasionally the client time goes up to 3000 milliseconds (but never higher than 3200 ms) even though the server time is still within acceptable limits.
I'm starting to think that a timeout is somewhere defined but I don't know where it might be. It´s not in my code and I've looked around on the developer site and google without results.
I'm hoping that someone can give me some clues where this delay might be defined and confirm that it is 3000 ms by default.
private String DownloadText(String URL)
{
String str = "";
int BUFFER_SIZE = 2000;
InputStream in = null;
try{
in = OpenHttpConnection(URL);
} catch (IOException e1) {
e1.printStackTrace();
return "";
}
catch(ArithmeticException ae){
//
}
try{
InputStreamReader isr = new InputStreamReader(in);
int charRead;
char[] inputBuffer = new char[BUFFER_SIZE];
try {
while ((charRead = isr.read(inputBuffer))>0)
{
//---convert the chars to a String---
String readString =
String.copyValueOf(inputBuffer, 0, charRead);
str += readString;
inputBuffer = new char[BUFFER_SIZE];
}
in.close();
} catch (IOException e) {
e.printStackTrace();
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
with
private InputStream OpenHttpConnection(String urlString) throws IOException {
InputStream in = null;
int response = -1;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
if (!(conn instanceof HttpURLConnection)) throw new IOException("Not an HTTP connection");
try{
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
}
catch (Exception ex) {
throw new IOException("Error connecting");
}
return in;
}
BTW: I borrowed the two functions from one of google's search results.
EDIT: I am calling DownloadText(url) from within a thread. I was beginning to think that could have something to do with the timeout. Does it ?
This will help you:
private static final int CONNECT_TIMEOUT_MILL = 10000;
private static final int READ_TIMEOUT_MILL = 3000;
....
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(CONNECT_TIMEOUT_MILL);
con.setReadTimeout(READ_TIMEOUT_MILL);
....
I've seen similar behavior like this before. In my case it was in AJAX calls and it was a real head puzzler for me too. It turned out in my case that the server was returning the data without either
specifying the content length or
closing the http connection
So the browser had to wait for the connection to timeout before it would process the data and generate the receive event. Something similar might be happening in your case, so break out the network analysis software and verify the http correctness. I normally use Fiddler2 for this type of work, but I don't know if you can make the android device go through a proxy very well. It sounds like you control the web server, so maybe inspecting the tcp packets from that end is possible.

Categories

Resources