问题
I have this URL https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3
. There is a PNG image on this URL address in blob storage accessible without any headers (normally) on the REST API. It opens normally from the web browser (e.g. Chrome). However, any attempt to load it in Java Android application to ImageView fails miserably. I have tried Volley, Picasso, Glide, Retrofit and manual methods. I include some code I have tried. The closest I have got to it produces this error message D/skia: --- Failed to create image decoder with message 'unimplemented'
. The problem is that the content type is image/png
, but I can't specify it anywhere and since the URL does not contain any extension, it proves rather problematic to decode. If you run the GET request through the API client (e.g. Postman), it will return a PNG file.
Same issue is present with this URL https://speakyfox-api-qa.herokuapp.com/api/v1/files/7b6f4529-256f-43a4-ac45-8613d96c505e
. It contains a short MP3 file that I wish to put into MediaPlayer object.
Before shouting that it is a one liner, I would appreciate you trying to get the image displayed in ImageView. The issue is that the link is for html and not directly to data.
// Getting reference to ImageView object
ImageView imageView = (ImageView)findViewById(R.id.imageView);
// Loading using Picasso
Picasso.get().load("https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3").into(imageView);
// Loading using Glide
Glide.with(MainActivity.this).load("https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3").into(imageView);
// Loading using HttpURLConnection/InputStream/Bitmap executed in Async task
java.net.URL url = new java.net.URL("https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
imageView.setImageBitmap(myBitmap);
// Using Volley [ImageRequest]
RequestQueue queue = Volley.newRequestQueue(this);
ImageRequest request = new ImageRequest("https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3", new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, Bitmap.Config.RGB_565, null){
/** Passing some request headers* */
@Override
public Map getHeaders() {
HashMap headers = new HashMap();
headers.put("Content-type","image/png");
return headers;
}
queue.add(request);
// Using Volley [NetworkImageView]
NetworkImageView networkImageView = (NetworkImageView) findViewById(R.id.networkImageView);
RequestQueue mRequestQueue = Volley.newRequestQueue(this);
ImageLoader mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
});
networkImageView.setImageUrl("https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3", mImageLoader);
// Using Volley [StringRequest]
RequestQueue queue = Volley.newRequestQueue(this);
StringRequest getRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
byte[] decodedString = Base64.decode(response, Base64.URL_SAFE);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
imageView.setImageBitmap(decodedByte);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {}
}) {
/** Passing some request headers* */
@Override
public Map getHeaders() {
HashMap headers = new HashMap();
headers.put("Content-type","image/png");
return headers;
}
};
queue.add(getRequest);
This code, however, works (but is ugly)...
WebView webView = findViewById(R.id.webview);
webView.loadUrl("https://speakyfox-api-qa.herokuapp.com/api/v1/files/7b6f4529-256f-43a4-ac45-8613d96c505e");
Nevertheless, I need to make it work with ImageView.
EDIT: I have tried downloading the file with OkHttp using this code
Request request = new Request.Builder().url(url).addHeader("Content-Type", "image/png").build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
call.enqueue(new Callback() {
public void onResponse(Call call, Response response) throws IOException {
Log.e("",response.body().string());
}
public void onFailure(Call call, IOException e) {}
});
The response body is
{"code":{"group":3,"internalCode":200,"statusCode":200},"data":{"type":"Image","imageType":"Whole","name":"I and you.png","size":67710,"contentType":"image/png","id":"db296f16-3283-4ba5-a32b-52b9feb64764","modified":"2019-10-16T20:44:20.468276Z"}}
回答1:
The image in question is 1.6MB as a PNG and is 5610 x 3963 pixels in size. Of particular note:
There is no mainstream Android device right now with a screen of that resolution (or similar resolutions)
That image will take up about 85MB of heap space
Most likely, your problem is that the image is simply too large and you are unable to allocate an 85MB block of memory for the decoded image. Either:
Reduce the image resolution by a fair bit along each axis, or
Download the image to a file (e.g., using OkHttp), then use Subsampling Scale Image View or a similar library that can handle displaying large images better
回答2:
The issue is that the link is for html and not directly to data.
Indeed. And an ImageView will not display html.
So you know the reason.
This is the html of the first link:
<html><head><meta name="viewport" content="width=device-width; height=device-height;"><link rel="stylesheet" href="resource://content-accessible/ImageDocument.css"><link rel="stylesheet" href="resource://content-accessible/TopLevelImageDocument.css"><link rel="stylesheet" href="chrome://global/skin/media/TopLevelImageDocument.css"><title>be28dcec-4912-4f58-8cb8-12b9b2948fc3 (PNG-afbeelding, 5610 × 3963 pixels) - Geschaald (13%)</title></head><body><img src="https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3" alt="https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3" class="transparent shrinkToFit" width="746" height="527"></body></html>
You better take a WebView.
回答3:
I have found a solution. I have copied all request headers that were added automatically in Postman. I have left just two. The headers make the server return not the html but the image itself. I couldn’t make it work with most methods specified above but one of them worked just fine.
RequestQueue queue = Volley.newRequestQueue(this);
ImageRequest request = new ImageRequest(url, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, ImageView.ScaleType.CENTER_INSIDE, null, null){
/** Passing some request headers* */
@Override
public Map getHeaders() {
HashMap headers = new HashMap();
headers.put("Accept","*/*");
headers.put("Cache-Control","no-cache");
return headers;
}
};
queue.add(request);
There is another constructor (without ImageView.ScaleType.CENTER_INSIDE) but it is marked as deprecated. It works perfectly well even with large image like the one in the specified URL (it takes a second to load though). The only issue is the warning from OkHttp saying that the connection is leaking.
来源:https://stackoverflow.com/questions/59147793/how-to-load-image-without-file-extension-from-url-to-imageview-in-android