java Android:使用 ThreadSafeClientConnManager 下载图像的错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1630258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 17:20:51  来源:igfitidea点击:

Android: Bug with ThreadSafeClientConnManager downloading images

javaandroidthread-safetyhttpclientbugfender

提问by znq

For my current application I collect images from different "event providers" in Spain.

对于我当前的应用程序,我从西班牙的不同“事件提供商”收集图像。

  Bitmap bmp=null;
  HttpGet httpRequest = new HttpGet(strURL);

  long t = System.currentTimeMillis();
  HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);
  Log.i(TAG, "Image ["+ strURL + "] fetched in [" + (System.currentTimeMillis()-t) + "ms]");

     HttpEntity entity = response.getEntity();
     InputStream instream = entity.getContent();
     bmp = BitmapFactory.decodeStream(instream);

     return bmp;

However, when downloading images from salir.com I get the following logcat output:

但是,从 salir.com 下载图像时,我得到以下 logcat 输出:

13970     Gallery_Activity  I  Fetching image 2/8 URL: http://media.salir.com/_images_/verticales/a/0/1/0/2540-los_inmortales_la_trattoria-marc_aureli_27_29_no.jpg
13970     ServiceHttpRequest  I  Image [http://media.salir.com/_images_/verticales/a/0/1/0/2540-los_inmortales_la_trattoria-marc_aureli_27_29_no.jpg] fetched in [146ms]
13970     skia  D  --- decoder->decode returned false

A search for that error message didn't provide much useful results.

搜索该错误消息并没有提供太多有用的结果。

Anyone an idea what the problem could be?

任何人都知道问题可能是什么?

Gracias!

谢谢!



Update 1:

更新 1:

After inquiring a bit more and testing different stuff I figured out that the problem seems to lie somewhere else. Even though my logcat output says

在询问了更多并测试了不同的东西之后,我发现问题似乎出在其他地方。即使我的 logcat 输出说

13970     ServiceHttpRequest  I  Image [http://media.salir.com/_images_/verticales/a/0/1/0/2540-los_inmortales_la_trattoria-marc_aureli_27_29_no.jpg] fetched in [146ms]
getContentLength(): 93288

which is the correct length of the image in bytes it seems that there's something wrong with the stream or HTTP connection.

这是图像的正确长度(以字节为单位),流或 HTTP 连接似乎有问题。

My original code (above) is taking advantage of the ThreadSafeClientConnManager. If I replace it with just a simple URLConnectionit works perfectly:

我的原始代码(以上)正在利用ThreadSafeClientConnManager。如果我只用一个简单的替换它,URLConnection它就可以完美运行:

URL url = new URL(strURL);
URLConnection conn = url.openConnection();
conn.connect();
InputStream instream = conn.getInputStream();
bmp = BitmapFactory.decodeStream(instream);

So, I'm wondering now why does my ThreadSafeClientConnManagerwork flawlessly (at least it seems it does) with all my other connections (mostly exchanging JSONObjects) but not with images from some specific websites (e.g. salir.com - for most other websites it works, though). Is there a HTTP parameter I'm missing?

所以,我现在想知道为什么我的ThreadSafeClientConnManager工作完美无缺(至少看起来是这样)与我的所有其他连接(主要是交换JSONObjects)而不是来自某些特定网站(例如 salir.com - 对于大多数其他网站它有效,尽管)。是否有我遗漏的 HTTP 参数?

My current setup is:

我目前的设置是:

HttpParams parameters = new BasicHttpParams();
HttpProtocolParams.setVersion(parameters, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(parameters, HTTP.UTF_8);
HttpProtocolParams.setUseExpectContinue(parameters, false); // some webservers have problems if this is set to true
ConnManagerParams.setMaxTotalConnections(parameters, MAX_TOTAL_CONNECTIONS);
HttpConnectionParams.setConnectionTimeout(parameters, CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(parameters, SOCKET_TIMEOUT);

SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", 
     PlainSocketFactory.getSocketFactory(), HTTP_PORT));

ClientConnectionManager conMgr = new ThreadSafeClientConnManager(parameters,schReg);

DefaultHttpClient http_client = new DefaultHttpClient(conMgr, parameters);


Update 2:

更新 2:

Now, the strange thing is, that it actually does work with the ThreadSafeClientConnManager-sometimes-. If I keep trying downloading the image and decoding it for a couple of times in a row it might work after 15-30 trials. Very strange.

现在,奇怪的是,它实际上确实与ThreadSafeClientConnManager-sometimes- 一起工作。如果我继续尝试下载图像并连续解码几次,它可能会在 15-30 次试验后工作。很奇怪。

I hope there's a solution to that since I would prefer using the ThreadSafeClientConnManagerinstead of URLConnection.

我希望有一个解决方案,因为我更喜欢使用ThreadSafeClientConnManager而不是URLConnection.



Update 3:

更新 3:

As suggest by Mike Mosher below, it seems that by using BufferedHttpEntitythe decoding errordoesn't appear any more. However now, even though less often than before, I get a SkImageDecoder::Factory returned nullerror.

正如迈克·莫舍以下建议,似乎用BufferedHttpEntity解码错误不会出现了。但是,现在,即使比以前少了,我也会收到SkImageDecoder::Factory returned null错误消息。

回答by Mike Mosher

Stefan,

斯蒂芬,

I've had the same issue, and didn't find much searching the internet. Many people have had this issue, but not alot of answers to solve it.

我也遇到了同样的问题,在网上搜索也没有找到。很多人都遇到过这个问题,但没有很多答案来解决它。

I was fetching images using URLConnection, but I found out the issue doesn't lie in the download, but the BitmapFactory.decodeStream was having an issue decoding the image.

我正在使用 URLConnection 获取图像,但我发现问题不在于下载,而是 BitmapFactory.decodeStream 解码图像时出现问题。

I changed my code to reflect your original code (using httpRequest). I made one change, which I found at http://groups.google.com/group/android-developers/browse_thread/thread/171b8bf35dbbed96/c3ec5f45436ceec8?lnk=raot(thanks Nilesh). You need to add "BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity); "

我更改了代码以反映您的原始代码(使用 httpRequest)。我做了一个更改,我在http://groups.google.com/group/android-developers/browse_thread/thread/171b8bf35dbbed96/c3ec5f45436ceec8?lnk=raot(感谢 Nilesh)上找到了它。您需要添加“BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);”

Here was my previous code:

这是我之前的代码:

        conn = (HttpURLConnection) bitmapUrl.openConnection(); 
        conn.connect();
        is = conn.getInputStream();
        //bis = new BufferedInputStream(is);
        //bm = BitmapFactory.decodeStream(bis);
        bm = BitmapFactory.decodeStream(is);

And her is the code that works:

她是有效的代码:

            HttpGet httpRequest = null;

    try {
        httpRequest = new HttpGet(bitmapUrl.toURI());
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }

    HttpClient httpclient = new DefaultHttpClient();
        HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);

        HttpEntity entity = response.getEntity();
        BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity); 
        InputStream instream = bufHttpEntity.getContent();
        bm = BitmapFactory.decodeStream(instream);

As I said, I have a page that download around 40 images, and you can refresh to see the most recent photos. I would have almost half fail with the "decoder->decode returned false error". With the above code, I have had no problems.

正如我所说,我有一个可以下载大约 40 张图片的页面,您可以刷新以查看最近的照片。由于“解码器-> 解码返回错误错误”,我几乎会失败一半。使用上面的代码,我没有遇到任何问题。

Thanks

谢谢

回答by capecrawler

My solution is not to use BitmapFactory.decodeStream()cause the way I look at it, it uses the SKIA decoder and it seems kind of erratic sometimes. You can try something like this.

我的解决方案不是使用BitmapFactory.decodeStream()我看待它的方式,它使用 SKIA 解码器,有时看起来有点不稳定。你可以尝试这样的事情。

    Bitmap bitmap = null;
    InputStream in = null;
    BufferedOutputStream out = null;
    try {
            in = new BufferedInputStream(new URL(url).openStream(),
                     IO_BUFFER_SIZE);

            final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
            out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
            copy(in, out);
            out.flush();

            final byte[] data = dataStream.toByteArray();
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);


   } catch (......){

   }        

and for the copy() function

和 copy() 函数

private static void copy(InputStream in, OutputStream out) throws IOException {
    byte[] b = new byte[IO_BUFFER_SIZE];
    int read;
    while ((read = in.read(b)) != -1) {
        out.write(b, 0, read);
    }
}

and IO_BUFFER_SIZEis a constant integer with the value of 4 * 1024.

并且IO_BUFFER_SIZE是一个值为 4 * 1024 的常量整数。

回答by Temujin

This is a Android bug. Your code is ok. "Android's decoders do not currently support partial data on decode." If you got image in entity probably it's a partial input stream, and android can't cope with that at the moment.

这是一个安卓错误。你的代码没问题。“Android 的解码器目前不支持解码部分数据。” 如果实体中有图像,则可能是部分输入流,而 android 目前无法处理。

Solution is to use FlushedInputStream from this thread: http://code.google.com/p/android/issues/detail?id=6066

解决方案是从这个线程使用 FlushedInputStream:http: //code.google.com/p/android/issues/detail?id=6066

回答by JFer

HttpGet httpRequest = null;
try {
  httpRequest = new HttpGet(url);
} catch (Exception e) {
  e.printStackTrace();
}
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity); 
InputStream instream = bufHttpEntity.getContent();
Bitmap bm = BitmapFactory.decodeStream(instream);

回答by gregm

Also try adding this option.

也可以尝试添加此选项。

opt.inPurgeable = true;

回答by Matt Rutkowsky

HttpURLConnection hConn = null;
        hConn = openHttpConnection(szUrl);

        hConn.setRequestMethod("GET");  
        hConn.setRequestProperty("User-Agent",szUserAgent);
        hConn.setRequestProperty("Accept",szAccept);
        hConn.setRequestProperty("Accept-Charset",szCharset);

        hConn.setInstanceFollowRedirects(true);
        hConn.setUseCaches(true);
        hConn.setChunkedStreamingMode(8*1024);
        hConn.setDoInput(true);
        hConn.setConnectTimeout(60*1000);
        hConn.setReadTimeout(60*1000);
        hConn.connect();


        InputStream bmpIs = hConn.getInputStream();
        BufferedInputStream bmpBis = new BufferedInputStream(bmpIs); 
        Bitmap bmpThumb = null;

        BitmapFactory.Options bfOpt = new BitmapFactory.Options();

        bfOpt.inScaled = true;
        bfOpt.inSampleSize = 2;
        bfOpt.inPurgeable = true;

        bmpThumb = BitmapFactory.decodeStream(bmpBis,null,bfOpt);

        if(bmpThumb == null)
        {
            for(int i=0; i<10; i++)
            {
                Thread.sleep(200);
                System.gc();

                bmpThumb = BitmapFactory.decodeStream(bmpBis,null,bfOpt);


                if(bmpThumb == null)
                    bfOpt.inSampleSize += 1;
                else
                    break;
            }
        }

回答by seanhodges

I had the exact same problem when trying to decode an image from a byte array. After some experimentation, the solution appears to be to assign some temp storage in the Options of the BitmapFactory. Try:

尝试从字节数组解码图像时,我遇到了完全相同的问题。经过一些实验,解决方案似乎是在 BitmapFactory 的 Options 中分配一些临时存储。尝试:

Options options = new Options();
options.inTempStorage = new byte[256];
Bitmap newMapBitmap = BitmapFactory.decodeStream(instream, null, options);

If the problem is not resolved straight away, try increasing the size of the temp array. I think large bitmap files need a larger buffer for decoding.

如果问题没有立即解决,请尝试增加临时数组的大小。我认为大型位图文件需要更大的缓冲区进行解码。

回答by Cross_

Setting the default buffer in Options does help with some out of memory issues regarding BitmapFactory but certainly does not cover all of them. The underlying issue appears to be some kind of timeout when retrieving the bitmap or the bitmap header. I am now writing the stream to a temp file and then pass the temp file to BitmapFactory which is working fine.

在 Options 中设置默认缓冲区确实有助于解决一些有关 BitmapFactory 的内存不足问题,但肯定不会涵盖所有这些问题。潜在的问题似乎是检索位图或位图标头时的某种超时。我现在正在将流写入临时文件,然后将临时文件传递给工作正常的 BitmapFactory。

回答by jfarrell

I was having a similar problem, and the root issue was due to timeouts when requesting some images. I switched to using a Background Image Loaderand have had no problems since. Hope this helps

我遇到了类似的问题,根本问题是由于请求某些图像时超时。我改用背景图像加载器,从那以后就没有问题了。希望这可以帮助

回答by Oskar

I've tried tree diffrent ways now, the simple URLConnection you use and that seems to be working for you, the way Mike Mosher uses and also this way [http://asantoso.wordpress.com/2008/03/07/download-and-view-image-from-the-web/]they all result in decode returned false.

我现在已经尝试了不同的树方式,你使用的简单 URLConnection 似乎对你有用,Mike Mosher 使用的方式也是这种方式 [ http://asantoso.wordpress.com/2008/03/07/download -and-view-image-from-the-web/]它们都导致解码返回 false。

HOWEVER if I convert the image to a PNG all of the ways work fine!! However I tried putting the images on my work ftp homepage and then all jpgs load fine with the simple solution... So for some reason it seems that if the server isn't fast enough it parses the jpg files before they are actually fully downloaded or something.

但是,如果我将图像转换为 PNG,则所有方法都可以正常工作!!但是,我尝试将图像放在我的工作 ftp 主页上,然后所有 jpg 都可以通过简单的解决方案正常加载...或者其他的东西。