I am working on an application that downloads images from a url. The problem is that only some images are being correctly downloaded and others are not. First off, here is the problem code:
public Bitmap downloadImage(String url) {
HttpClient client = new DefaultHttpClient();
HttpResponse response = null;
try {
response = client.execute(new HttpGet(url));
} catch (ClientProtocolException cpe) {
Log.i(LOG_FILE, "client protocol exception");
return null;
} catch (IOException ioe) {
Log.i(LOG_FILE, "IOE downloading image");
return null;
} catch (Exception e) {
Log.i(LOG_FILE, "Other exception downloading image");
return null;
}
// Convert images from stream to bitmap object
try {
Bitmap image = BitmapFactory.decodeStream(response.getEntity().getContent());
if(image==null)
Log.i(LOG_FILE, "image conversion failed");
return image;
} catch (Exception e) {
Log.i(LOG_FILE, "Other exception while converting image");
return null;
}
}
So what I have is a method that takes the url as a string argument and then downloads the image, converts the HttpResponse stream to a bitmap by means of the BitmapFactory.decodeStream method, and returns it. The problem is that when I am on a slow network connection (almost always 3G rather than Wi-Fi) some images are converted to null--not all of them, only some of them. Using a Wi-Fi connection works perfectly; all the images are downloaded and converted properly.
Does anyone know why this is happening? Or better, how can I fix this? How would I even go about testing to determine the problem? Any help is awesome; thank you!
This is a known issue with the JPEG decoder. There are two solutions. Either you download the entire image in a byte[] array using a ByteInputStream and then decode the array (this is what I do in code.google.com/p/shelves.) Another solution is to create a wrapper InputStream as shown below:
public class PatchInputStream extends FilterInputStream {
public PatchInputStream(InputStream in) {
super(in);
}
public long skip(long n) throws IOException {
long m = 0L;
while (m < n) {
long _m = in.skip(n-m);
if (_m == 0L) break;
m += _m;
}
return m;
}
}
Even with a WiFi connection some bitmaps (in particular .BMPs) will not be decoded. It's just a buggy decoder that can not deal with delays. If you search stackoverflow you will find some other solutions such as wrapping the HTTP stream in a buffered http entity. That works but depending on image size can take up a lot of memory. For our commerical product we ended up downloading the http stream to sdcard and then using Bitmapfactory on the dowloaded file. It's somewhat slower but 100% reliable.