All was perfect before I realize that some of my images doesn't load because of HTTP code 302 - moved temporary or "The data requested actually resides under a different URL". So this means my request is redirected with "Location" header. I found that Android do not support any redirect following - with RedirectHandler or anything else (in SDK v2.3).
I solved my problem with simply reading headers, finding Location header and recursively call downloading method again. Warning: This technique does not prevent circular redirects, so you have to check for them on your own. Here is my method:
private static Bitmap downloadBitmap(String url) { final AndroidHttpClient client = AndroidHttpClient.newInstance("Android"); final HttpGet request = new HttpGet(url); try { HttpResponse response = client.execute(request); final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { Header[] headers = response.getHeaders("Location"); if (headers != null && headers.length != 0) { String newUrl = headers[headers.length - 1].getValue(); // call again with new URL return downloadBitmap(newUrl); } else { return null; } } final HttpEntity entity = response.getEntity(); if (entity != null) { InputStream inputStream = null; try { inputStream = entity.getContent(); // do your work here return BitmapFactory.decodeStream(inputStream); } finally { if (inputStream != null) { inputStream.close(); } entity.consumeContent(); } } } catch (Exception e) { request.abort(); } finally { if (client != null) { client.close(); } } return null; }
Lets all hope Google engineers will fix following redirects in future versions of Android SDK
Edit
I have found that you shouldn't use AndroidHttpClient but instead use HttpUrlConnection. This class follows up to 5 redirects and supports cache. Here is the improved code snippet:private static Bitmap downloadBitmap(String stringUrl) { URL url = null; HttpURLConnection connection = null; InputStream inputStream = null; try { url = new URL(stringUrl); connection = (HttpURLConnection) url.openConnection(); connection.setUseCaches(true); inputStream = connection.getInputStream(); return BitmapFactory.decodeStream(new FlushedInputStream(inputStream)); } catch (Exception e) { Log.w(TAG, "Error while retrieving bitmap from " + stringUrl, e); } finally { if (connection != null) { connection.disconnect(); } } return null; }
Problem of url.openConnection() is that it doesn't allow redirect from http to https and vice versa :-(
ReplyDeleteBut AndroidHttpClient support redirect. You can use this
HttpClientParams.setRedirecting(client.getParams(), true);
This comment has been removed by the author.
ReplyDeletethank you so much. still works today, nearly 20 months since it's post.
ReplyDeleteThat's work very well
ReplyDeletethanks
Still getting error decoder-decode false
ReplyDeleteprivate static Bitmap downloadBitmap(String stringUrl) {
URL url = null;
HttpURLConnection connection = null;
InputStream inputStream = null;
try {
url = new URL(stringUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(true);
inputStream = connection.getInputStream();
return BitmapFactory.decodeStream(new FlushedInputStream(inputStream));
} catch (Exception e) {
Log.w("e", "Error while retrieving bitmap from " + stringUrl, e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int byteValue = read();
if (byteValue < 0) {
break; // we reached EOF
} else
{
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
thank you so very much!! solved my problem!!
ReplyDelete