I'm writing an app for both iOS and Android, and both are native (no PhoneGap, no Titanium). The app's general behavior is to GET an XML file from a server, parse it, and based on its contents GET some number of other XML files as well as to download some extra data files ( PDFs, images, etc ). It's a bit like RSS.
An initial load on iOS (when I've cleared local caches so everything has to be pulled down) takes about 20 seconds. Less than 1 second for the main feed, and 19 or 20 for the rest of the content.
On Android, it takes about two minutes.
Now, early on I found that XML parsing was a big hit so I dropped XmlPullParser and wrote a SAX parser which sped things up a bit (one XML file went from 20 seconds to parse down to 2, which is still really slow compared to iOS). But still, now that XML parsing is less of a factor in performance, the network performance is killing me.
I've googled and found a lot of threads on exactly this. I've tried a bunch of different approaches, none of which have done anything and it feels like guesswork more than engineering.
For example, I've done this:
System.setProperty("java.net.preferIPv4Stack", "true");
System.setProperty("http.keepAlive", "false");
And on my HttpURLConnection, I've set it to use NO_PROXY and a shorter connect timeout, and to disallow caches.
HttpURLConnection c = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
c.setConnectTimeout(1000);
c.setUseCaches(false);
None has helped!
Clearly, Android's network stack works and it works quickly - various Android apps I've used that touch the network are perfectly quick. So clearly I'm doing something wrong. But what?
Please, help. I'm at wit's end here.
I've not solved the problem, but I've worked out what's going on. It was latency.
Android's HttpURLConnection apparently has a broken http keep-alive implementation
Maybe related to the above problem, http pipelining doesn't work either
I was synchronously making URL connections in a single AsyncTask - I tried various approaches to speed it up like doing all my connections one after another, saving their response bodies in memory and processing that later. That sped it up from 2 or 3 minutes seconds to about 1.5, but that was still unacceptable.
In a last desperate hope I tried AsyncHttpClient
And holy smokes, now the whole download takes about 20 seconds, just like it does on iOS.
So, word to the wise: If your android app makes a LOT of GETs to a service, and you can't rewrite that service to elide those GETs into a single big batch ( I couldn't here ) you do not want to use Android's HttpUrlConnection. Use AsyncHttpClient.
Unfortunately, AsyncHttpClient is structured like AFNetworking, which is a lot more awkward on Java than it is in ObjectiveC. So it will take some finagling. But it works really well.
Related
On performance view, JSON parsing take huge time for retrieving Data.In my app i need to get nearly 10,000 records from Server.On emulator,it gets data immediately and works efficiently.But in my android phone,it takes more than 2 minutes to retrieve all data.Kindly,give me a suggestion for improve the performance on phone.
The emulator has access to your host machine's resources and is therefore not a good way to test performance.
I have used the Jackson streaming JSON parser with large data sets and it works well for me. However, I run this process in the background and am able to accept long fetch/parse times. Depending on the size of the data and the speed of the device you're running on, 2 minutes does not seem extraordinarily long to me.
Maybe you could fetch a smaller subset of the data first, and then display it while you fetch the rest in the background. You're probably going to have to do some kind of optimization like this in order to improve performance.
I think you can parse the complex JSON response using GSON. Please check these tutorial http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html
You just create the model classes and use the proper annotations then the data will be parsed to model objects directly.
The question is, what causes this slowdown. Because of everything goes in the rmulator like charm, it is probably the network speed. You can help this if you find a solution to compress the json data.
It is a text, with a lot of repeat, it is very, very good compressable. And http supports compression.
You need to set it in your http server.
If you find this a promising direction, I suggest to make a new question, giving your http server version. Good luck!
Is there any example of using robospice library for downloading large files? I've read there is BigBinaryRequest for it but what if there will be connectivity lost/ device reboot duing file download? After next execute call download will resume/restart or request success listener will fire with reference to damaged (not completly downloaded) file?
Maybe someone have experience of using robospice for such requests.
P.S. I know that there is native DownloadManager in Android, but I think using robospice is easier. Maybe I'm wrong.
#rciovati got it right, your download, if interrupted will be lost as RS won't be able to load the result from the cache. Or even worse, you could have receive an uncomplete InputStream from the cache. In that case you should remove the cache content by yourself (using the spicemanager's method to achieve it is pretty easy).
If you download twice a large input stream using the same cache key, there is no protection against that in RS. Your cache will get corrupted.
This answer may give you the feeling that BigBinaryRequest is poorly designed and not working, but according to my own experience, it works fine in all cases I met up to now.
I need to download a big file on my app (almost 2gb) and i was wondering what is the best way to do that and some libs to help me.
First I looked the Android Asynchronous Http Library but I didn't find examples showing how to publish the progress or start, pause download. Then I don't know if should I use this lib or just use a standart http commons.
Other problem is, should I use a service to download my file??
Could you guys give a hint, how to do that?
I've see you got a bunch of answer and none of them really answers it from a holistic point of view.
To download a 2k or 2gb file the actual code is the same using some type of connection handler and some type of input stream and output stream and usually wrapping the input stream with a buffered input stream. For that you can find infinite amount of java examples all around the web.
The trick here considering the Android platform is that because it's a lengthy operation, you shouldn't be doing it inside the activity life cycle at all.
Said that you have two options:
as you suggested you can create a Service, I would suggest you to use the IntentService
as it seems to be a perfect fit for this case. The IntentService automatically spans a new thread, through the intent you pass the URL as a String and let the service download using the streams, etc.
another method that probably work well, but I've never personally used, is to use the DownloadManager that is available since Gingerbread. It shouldn't be difficult to call getSystemService(Context.DOWNLOAD_SERVICE) and call dwManag.enqueue(dwRequest);
hope it helps.
If you're not targeting pre-Gingerbread devices, I would use DownloadManager as suggested as the third option in the answer you linked to. It takes care of downloading the file, displays the progress in the notification bar so that the user can see what's going on even after your app has gone into the background and you don't have to worry so much about what happens when the user goes into another app and android decides to kill your app to free memory. Also, it works with features like "only download files over wifi" that at least some android builds have.
I suggest you to use adm download manager. Downloads never fail even if there is no network and the speed is also best.
After some googling, I selected various sources and started to use a separate thread to download images to make the UI responsive. It actually worked like a charm. But after a few minutes it would freeze the emulator. Initially I had assumed various reasons but finally I figured out that if this threading code is removed it works without freezing the emulator.
The code was adapted from another Stackoverflow question from the answer given by a certain Fedor. For the sake of simplicity I had removed the HashMap part and directly download the image each time a request comes from the list adapter. Also, I assumed that since the image is very small (< 1 KiB) it can actually be downloaded again rather than storing it in memory.
I am not sure if this is the right way to handle asynchronous image download, but any help in preventing the emulator freeze would be much appreciated. I can copy paste the code if needed.
Have a look at this url
about downloading images from remote server using asynchronous task and threadpool.
I'm building an app that fetches XML from a server, then parses it (it's DIDL formatted in places). The goal is to load as much into memory as possible to make it easier for users to browse (so as to enable fast scrolling through results), but I keep getting OutOfMemoryErrors. I'm kind of new to Android, and it seems like the VMs are really finicky about things. I'm loading no more than a megabyte of XML, and pretty much discarding it right away. What should I do to prevent these errors from happening?
Should I load chunk by chunk of the file over the network, write it to disk, then load chunk by chunk back into and out of memory, parsing everything into POJOs? If it can be avoided, I'd like to not have to implement some form of pagination, as per the Twitter app (it used to load more entries when you hit the bottom, it now loads a lot all at once and likewise crashes with an OOM error.) I'm running a Nexus One if that helps, CM7/Android 2.3.3.
You can read this nice article about XML parsing on Android. Using pull parser would be good choice for you, since it does not need to read complete document into the memory, which is the problem in your case. I would suggest that you store parsed results into the database, since once they are there, you can quickly do list them and page them any way you want, and performance of the DB is great. This way, you need to do loading of complete data from server to DB just once (if data is not changing on the server) or to load it once and then to get updates from time to time if it is changing (like in case of twitter).
Move all your object declarations out of loops and nullify them after the use. And use System.gc() frequently (beleive me, it works). Use class level objects as less as you can. Execute your app and keep watch on the Logcat logs.