Android:ThreadSafeClientConnManager 下载图像的错误

发布于 2024-08-08 21:04:00 字数 3423 浏览 9 评论 0原文

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

  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;

但是,当从 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

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

有人知道问题可能是什么吗?

谢谢!


更新1:

在询问了更多并测试了不同的东西之后,我发现问题似乎出在其他地方。尽管我的 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

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

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

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

所以,我现在想知道为什么我的 ThreadSafeClientConnManager 可以完美地工作(至少看起来如此)我的其他连接(主要是交换 JSONObjects ),但不与某些特定网站的图像(例如 salir.com - 但对于大多数其他网站来说它可以工作)。我是否缺少 HTTP 参数?

我当前的设置是:

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

更新 2:

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

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


更新3:

正如下面Mike Mosher的建议,似乎通过使用BufferedHttpEntity 解码错误不再出现。然而现在,尽管比以前少了,但我还是收到 SkImageDecoder::Factory returned null 错误。

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:

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:

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

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.

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

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 ThreadSafeClientConnManager work 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?

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:

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.

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


Update 3:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

打小就很酷 2024-08-15 21:04:00

Stefan,

我也遇到了同样的问题,但在互联网上搜索并没有找到太多信息。很多人都遇到过这个问题,但没有太多答案可以解决。

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

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

这是我之前的代码:

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

她是有效的代码:

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

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

谢谢

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.

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

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.

Thanks

猫七 2024-08-15 21:04:00

我的解决方案是不使用 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 (......){

   }        

对于 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);
    }
}

IO_BUFFER_SIZE 是一个常量整数,值为 4 * 1024。

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.

    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

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_SIZE is a constant integer with the value of 4 * 1024.

谁对谁错谁最难过 2024-08-15 21:04:00

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

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

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.

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

苏大泽ㄣ 2024-08-15 21:04:00

也尝试添加此选项。

opt.inPurgeable = true;

Also try adding this option.

opt.inPurgeable = true;
白衬杉格子梦 2024-08-15 21:04:00
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);
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);
娇纵 2024-08-15 21:04:00

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

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 Loader and have had no problems since. Hope this helps

叹沉浮 2024-08-15 21:04:00

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

但是,如果我将图像转换为 PNG,所有方法都可以正常工作!不过,我尝试将图像放在我的工作 ftp 主页上,然后使用简单的解决方案可以很好地加载所有 jpg...因此,出于某种原因,似乎如果服务器速度不够快,它会在 jpg 文件实际完全下载之前解析它们或者什么的。

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.

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.

花辞树 2024-08-15 21:04:00

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

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

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

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:

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.

仄言 2024-08-15 21:04:00

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

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.

2024-08-15 21:04:00

即使我将整个文件下载到缓冲区,然后将字节数组解码为位图,我大约有八次遇到此错误“SkImageDecoder::Factory returned null”。我尝试了以下方法,但没有一个对我有用:

  • 仅使用 URL,而不是 http 连接类型
  • 缓冲阅读器
  • 下载整个文件,然后进行解码

我不相信刷新的输入流解决方法会起作用。
这似乎确实是 Android 滑雪错误。人们仍然在这里报告问题:
http://code.google.com/p/android/issues/detail ?id=6066
除了在位图为空时重试之外,我没有解决此错误的方法,这只会减少出现错误的机会。

I experience this error “SkImageDecoder::Factory returned null” about 1 out of 8 times, even if I download the entire file to a buffer, then decode the byte array to a bitmap. I tried the following and none worked for me:

  • Using only URLs, not http connection types
  • Buffered readers
  • Download entire file, then do decode

I don’t believe the flushed input stream workaround would work either.
It does appear to be an Android skia bug. People are still reporting problems here:
http://code.google.com/p/android/issues/detail?id=6066.
I have no workaround for this bug except to retry if the bitmap is null, which only reduces the chances of getting the error.

柒夜笙歌凉 2024-08-15 21:04:00
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;
            }
        }
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;
            }
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文