I am making an HTTP get request to a website for an android application I am making.
I am using a DefaultHttpClient and using HttpGet to issue the request. I get the entity response and from this obtain an InputStream object for getting the html of the page.
I then cycle through the reply doing as follows:
BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
String x = "";
x = r.readLine();
String total = "";
while(x!= null){
total += x;
x = r.readLine();
}
However this is horrendously slow.
Is this inefficient? I'm not loading a big web page - www.cokezone.co.uk so the file size is not big. Is there a better way to do this?
Thanks
Andy
Source: Tips4all
The problem in your code is that it's creating lots of heavy String objects, copying all its contents and doing operations with them. To drastically improve it you should use StringBuilder, that avoid to instantiate new String objects on each append, it directly uses the internal char arrays without copy them. The implementation for your case would be something like that:
ReplyDeleteBufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line);
}
After that you can use total as a CharSequence for lots of cases without convert it to String. If you need to do it, use total.toString() after the loop.
I'll try to explain it better...
a += b (or a = a + b), being a and b Strings, copies a and b chars to a new object (note that you are also copying a, that contains the not-small accumulated String), and you are doing those copies on each iteration. Copying some Kbs and creating some objects lots of times is expensive.
a.append(b), being a a StringBuilder, directly appends b contents to a, so you don't copy the accumulated String on each iteration.
Have you tried the built in method to convert a stream to a string? It's part of the Apache Commons library (org.apache.commons.io.IOUtils).
ReplyDeleteThen your code would be this one line:
String total = IOUtils.toString(inputStream);
The documentation for it can be found here:
http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toString%28java.io.InputStream%29
The Apache Commons IO library can be downloaded from here:
http://commons.apache.org/io/download_io.cgi
What about this. Seems to give better performance.
ReplyDeletebyte[] bytes = new byte[1000];
StringBuilder x = new StringBuilder();
int numRead = 0;
while ((numRead = is.read(bytes)) >= 0) {
x.append(new String(bytes, 0, numRead));
}
Edit: Actually this sort of encompasses both steelbytes and Maurice Perry's
If the file is long, you can optimize your code by appending to a StringBuilder instead of using a String concatenation for each line.
ReplyDeletemaybe rather then read 'one line at a time' and join the strings, try 'read all available' so as to avoid the scanning for end of line, and to also avoid string joins.
ReplyDeleteie, InputStream.available() and InputStream.read(byte[] b, int offset, int length)