Android: ошибка с загрузкой изображений ThreadSafeClientConnManager - PullRequest
13 голосов
/ 27 октября 2009

Для моего текущего приложения я собираю изображения из разных "событий провайдеры "в Испании.

  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

Поиск этого сообщения об ошибке не дал много полезных результатов.

Кто-нибудь знает, в чем может быть проблема?

Gracias!


Обновление 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:

Как подсказывает Майк Мошер ниже, кажется, что при использовании BufferedHttpEntity ошибка декодирования больше не появляется. Однако теперь, хотя и реже, чем раньше, я получаю ошибку SkImageDecoder::Factory returned null.

Ответы [ 11 ]

27 голосов
/ 19 декабря 2009

Стефан,

У меня была такая же проблема, и я не нашел много поиска в Интернете. У многих людей была эта проблема, но не много ответов для ее решения.

Я выбирал изображения с помощью 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 изображений, и вы можете обновить ее, чтобы увидеть самые свежие фотографии. Я бы почти наполовину потерпел неудачу с «decoder-> decode return false error». С приведенным выше кодом у меня не было проблем.

Спасибо

5 голосов
/ 20 января 2010

Мое решение не в том, чтобы использовать 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.

3 голосов
/ 13 января 2011

Это ошибка Android. Ваш код в порядке. «Декодеры Android в настоящее время не поддерживают частичные данные при декодировании». Если у вас есть изображение в объекте, возможно, это частичный поток ввода, и Android не может справиться с этим в данный момент.

Решением является использование FlushedInputStream из этого потока: http://code.google.com/p/android/issues/detail?id=6066

2 голосов
/ 19 ноября 2010
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);
2 голосов
/ 02 ноября 2010

Также попробуйте добавить эту опцию.

opt.inPurgeable = true;
0 голосов
/ 01 октября 2011

Я сталкиваюсь с этой ошибкой «SkImageDecoder :: Factory return null» примерно 1 из 8 раз, даже если я загружаю весь файл в буфер, а затем декодирую массив байтов в растровое изображение. Я попробовал следующее, и никто не работал для меня:

  • Использование только URL-адресов, а не типов соединений http
  • Буферизованные читатели
  • Загрузите весь файл, затем выполните декодирование

Я не верю, что обходной путь очищенного входного потока тоже подойдет. Похоже, это ошибка Android Skia. Люди все еще сообщают о проблемах здесь: http://code.google.com/p/android/issues/detail?id=6066. У меня нет обходного пути для этой ошибки, за исключением повтора, если растровое изображение равно нулю, что только снижает вероятность получения ошибки.

0 голосов
/ 08 ноября 2010
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;
            }
        }
0 голосов
/ 09 сентября 2010

Установка буфера по умолчанию в Options помогает решить некоторые проблемы нехватки памяти, связанные с BitmapFactory, но, конечно, не охватывает все из них. Основная проблема заключается в том, что при извлечении растрового изображения или заголовка растрового изображения возникает тайм-аут. Теперь я записываю поток во временный файл, а затем передаю временный файл в BitmapFactory, который работает нормально.

0 голосов
/ 26 февраля 2010

У меня была точно такая же проблема при попытке декодировать изображение из байтового массива. После некоторых экспериментов решение, по-видимому, заключается в том, чтобы назначить некоторое временное хранилище в параметрах BitmapFactory. Попробуйте:

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

Если проблема не решена сразу, попробуйте увеличить размер временного массива. Я думаю, что для больших растровых файлов требуется больший буфер для декодирования.

0 голосов
/ 06 января 2010

Я пробовал разные способы дерева, простое соединение URLC, которое вы используете, и это, кажется, работает для вас, то, как использует Майк Мошер, а также таким образом [http://asantoso.wordpress.com/2008/03/07/download-and-view-image-from-the-web/] все они приводят к тому, что декодирование возвращает false.

ОДНАКО если я конвертирую изображение в PNG, все способы работают нормально !! Однако я попытался поместить изображения на мою рабочую домашнюю страницу ftp, а затем все jpgs нормально загружались с помощью простого решения ... Так что по какой-то причине кажется, что если сервер недостаточно быстр, он анализирует файлы jpg до того, как они фактически полностью загрузятся или что-то.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...