【问题标题】:How to load image without file extension from URL to ImageView in Android如何在Android中将没有文件扩展名的图像从URL加载到ImageView
【发布时间】:2019-12-02 22:50:15
【问题描述】:

我有这个网址https://speakyfox-api-qa.herokuapp.com/api/v1/files/be28dcec-4912-4f58-8cb8-12b9b2948fc3。在 Blob 存储中,此 URL 地址上有一个 PNG 图像,可在 REST API 上无需任何标头(通常)即可访问。它通常从网络浏览器(例如 Chrome)打开。然而,任何试图在 Java Android 应用程序中将其加载到 ImageView 的尝试都失败了。我尝试过 Volley、Picasso、Glide、Retrofit 和手动方法。我包括一些我尝试过的代码。我最接近它会产生此错误消息D/skia: --- Failed to create image decoder with message 'unimplemented'。问题是内容类型是image/png,但我无法在任何地方指定它,并且由于 URL 不包含任何扩展名,因此解码起来相当有问题。如果您通过 API 客户端(例如 Postman)运行 GET 请求,它将返回一个 PNG 文件。

此 URL https://speakyfox-api-qa.herokuapp.com/api/v1/files/7b6f4529-256f-43a4-ac45-8613d96c505e 存在同样的问题。它包含一个简短的 MP3 文件,我希望将其放入 MediaPlayer 对象中。

在大喊它是单线之前,我希望您尝试让图像显示在 ImageView 中。问题是该链接是针对 html 而不是直接指向数据。

// 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);

然而,这段代码可以工作(但很难看)...

WebView webView = findViewById(R.id.webview);
webView.loadUrl("https://speakyfox-api-qa.herokuapp.com/api/v1/files/7b6f4529-256f-43a4-ac45-8613d96c505e");

不过,我需要让它与 ImageView 一起工作。

编辑:我尝试使用此代码通过 OkHttp 下载文件

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) {}
});

响应正文是

{"code":{"group":3,"internalCode":200,"statusCode":200},"data":{"type":"Image","imageType":"Whole"," name":"我和你.png","size":67710,"contentType":"image/png","id":"db296f16-3283-4ba5-a32b-52b9feb64764","modified":"2019- 10-16T20:44:20.468276Z"}}

【问题讨论】:

  • "如果您通过 API 客户端(例如 Postman)运行 GET 请求,它将返回一个 PNG 文件" -- Web 服务是否设置了 Content-type HTTP 响应标头?如果没有,请添加它,它应该可以解决您的问题。
  • @CommonsWare,Postman 没有传递任何特殊的标头。我添加了标题,但它似乎不起作用......
  • “邮递员没有传递任何特殊的标题”——这不是我所指的。我指的是来自您的 Web 服务的响应。
  • 我会说下载并缓存它,然后在您的图像视图中预览缩略图
  • @CommonsWare,对不起,我误解了。是的,它返回 Content-type : image/png.

标签: java android imageview android-imageview networkimageview


【解决方案1】:

有问题的图片大小为 1.6MB(PNG),大小为 5610 x 3963 像素。特别注意:

  • 目前没有主流 Android 设备具有该分辨率(或类似分辨率)的屏幕

  • 该图像将占用大约 85MB 的堆空间

您的问题很可能是图像太大,您无法为解码后的图像分配 85MB 的内存块。要么:

【讨论】:

  • 我确实使用了另一个带有低分辨率图片的链接 (68KB - 600x400) speakyfox-api-qa.herokuapp.com/api/v1/files/… 归结为来自 Picasso/Glide: D/skia: --- SkAndroidCodec::NewFromStream 的相同错误返回空
  • @BernardoBellotto:那么无论是图像还是您的 Web 服务为它们提供服务的方式都有些奇怪。但是,即使您克服了网络(或其他)问题,您仍然会遇到图像太大的问题。
  • 我同意尺寸。问题是非常简单的 GET 请求在使用 Swift 的 iOS 上运行得非常好。根据服务器的编码器,这些文件作为 blob 存储在数据库中。当我尝试不以 .xxx 结尾的不同 URL 时,会出现下载问题。可能是安卓相关的问题什么的。
【解决方案2】:

问题是链接是针对 html 而不是直接指向数据。

确实如此。并且 ImageView 不会显示 html。

所以你知道原因了。

这是第一个链接的html:

&lt;html&gt;&lt;head&gt;&lt;meta name="viewport" content="width=device-width; height=device-height;"&gt;&lt;link rel="stylesheet" href="resource://content-accessible/ImageDocument.css"&gt;&lt;link rel="stylesheet" href="resource://content-accessible/TopLevelImageDocument.css"&gt;&lt;link rel="stylesheet" href="chrome://global/skin/media/TopLevelImageDocument.css"&gt;&lt;title&gt;be28dcec-4912-4f58-8cb8-12b9b2948fc3 (PNG-afbeelding, 5610&amp;nbsp;×&amp;nbsp;3963 pixels) - Geschaald (13%)&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;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"&gt;&lt;/body&gt;&lt;/html&gt;

你最好使用 WebView。

【讨论】:

    【解决方案3】:

    我找到了解决办法。我已经复制了在 Postman 中自动添加的所有请求标头。我只剩下两个了。标头使服务器返回的不是 html,而是图像本身。我无法使用上面指定的大多数方法使其工作,但其中一种工作正常。

    
    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);
    
    

    还有另一个构造函数(没有 ImageView.ScaleType.CENTER_INSIDE),但它被标记为已弃用。 即使使用像指定 URL 中的大图像(虽然加载需要一秒钟),它也能很好地工作。唯一的问题是来自 OkHttp 的警告说连接正在泄漏。

    【讨论】:

      猜你喜欢
      • 2014-11-10
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多