13

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

  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 -sometimes-。如果我继续尝试下载图像并连续解码几次,它可能会在 15-30 次试验后工作。很奇怪。

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


更新 3:

正如下面 Mike Mosher 所建议的那样,似乎通过使用BufferedHttpEntity解码错误不再出现。然而现在,即使比以前少了,我得到了一个SkImageDecoder::Factory returned null错误。

4

11 回答 11

27

斯特凡,

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

我正在使用 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 张图像的页面,您可以刷新以查看最新照片。由于“解码器->解码返回错误错误”,我几乎会失败一半。使用上面的代码,我没有任何问题。

谢谢

于 2009-12-19T04:14:17.627 回答
5

我的解决方案是不使用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。

于 2010-01-20T06:55:09.117 回答
3

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

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

于 2011-01-13T02:20:47.557 回答
2
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);
于 2010-11-19T03:03:24.333 回答
2

也尝试添加此选项。

opt.inPurgeable = true;
于 2010-11-02T18:52:35.867 回答
0

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

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

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

于 2011-10-01T19:05:56.113 回答
0

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

于 2010-09-09T00:14:16.343 回答
0

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

于 2009-10-30T14:48:55.747 回答
0

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

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

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

于 2010-02-26T11:07:43.143 回答
0

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

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

于 2010-01-06T17:03:25.873 回答
0
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;
            }
        }
于 2010-11-07T22:52:38.293 回答