Универсальный загрузчик изображений не может загружать изображения иногда

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

public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
  try
  {
    String fail = failReason.getType().toString();
    String fail4 = failReason.getCause().toString();
    String sum = fail + " " + fail4;
    EasyTracker.getTracker().sendException(sum, false);
  }
  catch (Exception e)
  {
    EasyTracker.getTracker().sendException(e.getMessage(), false);
  }
}

В большинстве случаев он получает исключение, поскольку getType или getCause равно null. Эта проблема наблюдается на устройствах с версиями Android 2.1-2.3, но есть несколько отчетов от более новой версии, например 4.0.4 или даже 4.2.2. Поэтому я не могу сказать, что заставило изображение не загружать

Другая проблема - IO_ERROR java.io.EOFException, которая чаще всего встречается на более новых версиях Android.

Третий из наиболее распространенных ошибок - ошибки out_of_memory... Изображения, которые я пытаюсь загрузить, не больше 1 Мб, но мне нужно иметь ScaleType.Exactly, но при загрузке больших изображений я не кэширую их в памяти или на диске, чтобы уменьшить возможность out_of_memory, но это все равно происходит довольно часто.

Моя конфигурация:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(xxx.getApplicationContext())
.threadPoolSize(4)
.memoryCache(new WeakMemoryCache())
.imageDownloader(new BaseImageDownloader(xxx.getApplicationContext(),10 * 1000, 30 * 1000)) 
.build();

if(!ImageLoader.getInstance().isInited())
            ImageLoader.getInstance().init(config);

// options is used for images smaller in size (5kb-150kb)
options = new DisplayImageOptions.Builder()
.cacheInMemory()
.cacheOnDisc()
.showStubImage(R.drawable.stub)
.showImageOnFail(R.drawable.failed)
.imageScaleType(ImageScaleType.EXACTLY)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();

// options2 is used for images big in size (300kb-1,2mb)
options2 = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.stub)
.showImageOnFail(R.drawable.failed)
.imageScaleType(ImageScaleType.NONE) // NONE because I need to have full size bitmap loaded
.bitmapConfig(Bitmap.Config.RGB_565)
.build();

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

Обновление Поскольку я изменил код как предложенный nostra на onLoadingFailed, теперь я вижу, что все отчеты, которые не имеют .getCause(), являются "DECODING_ERROR", и все они сообщаются версиями android 2.2-2.3.6, ни один из более новых из них. Но все же большая часть моих пользователей находится на старых андроидах, любая идея, как уменьшить этот decoding_error? Я сам проверил приложение на старых андроидах, а изображения загружаются большую часть времени, но DECODING_ERROR чаще всего сообщается в аналитике. Во-вторых, по самым популярным причинам все еще остается тот же IO_ERROR java.io.EOFException

Обновление 2

Пользовательский загрузчик, как предлагал nostra, уменьшил threadPoolSize до 3, установил дополнительную загрузку - если загрузка не удалась, попробуйте повторно загрузить за один раз перед тем, как отказаться. Я вижу, что потери при загрузке снизились примерно на 30%. Но все же встречаются 100 ошибок декодирования (исключительно только в версиях 2.2-2.3.6) и 160 ошибок EOF (4.0 и выше) за 3 дня от 500 активных пользователей ежедневно.

Обновление 3

В последней обновленной версии гораздо меньше ошибок декодирования и EOFExceptions, я думаю, в основном потому, что я пытаюсь перезагрузить один и тот же образ, если он не загружается в первый раз. Но теперь у меня возникает другая проблема: на устройстве java.io.IOException: write failed: ENOSPC (No space left on device) нет места. Я использую LimDiscCache.

Ответ 1

failReason.getType() не может быть null, но failReason.getCause() может. Вы должны проверить это, чтобы предотвратить NPE.

failReason.getCause() может быть null, если вы отклонили сеть по ImageLoader.denyNetworkDownloads(true) или произошла ошибка декодирования. Это связано с тем, что Android по какой-то причине не может декодировать изображение.

Кстати. Я рекомендую использовать .cacheOnDisc() даже для больших изображений (options2). И, возможно, попробуйте другую реализацию кэша памяти? Например. LruMemoryCache.

Я не знаю причину java.io.EOFException, но вы можете определить, какая сеть используется в это время? Мобильный или WiFi? Возможно, попробуйте использовать ImageLoader.handleSlowNetwork(boolean) для переключения между типами сети.

UPD: Также попробуйте уменьшить размер пула потоков. Возможно, это помогает предотвратить ОБОРОТНЫЕ ОШИБКИ. UPD2: Ошибка декодирования может быть вызвана перенаправлением веб-сайта на веб-страницу. Вы можете попробовать расширить BaseImageDownloader и добавить пустую строку для заголовка "User-Agent" в запросе.

public class MyImageDownloader extends BaseImageDownloader {

private static final int MAX_REDIRECT_COUNT = 5;

public MyImageDownloader(Context context) {
    super(context);
}

protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
    HttpURLConnection conn = connectTo(imageUri);

    int redirectCount = 0;
    while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
        conn = connectTo(conn.getHeaderField("Location"));
        redirectCount++;
    }

    return new BufferedInputStream(conn.getInputStream(), BUFFER_SIZE);
}

protected HttpURLConnection connectTo(String url) throws IOException {
    String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS);
    HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection();
    conn.setConnectTimeout(connectTimeout);
    conn.setReadTimeout(readTimeout);
    conn.setRequestProperty("User-Agent", "");
    return conn;
}
}

Или, так как UIL 1.8.5:

public class MyImageDownloader extends BaseImageDownloader {
    @Override
    protected HttpURLConnection createConnection(String url) throws IOException {
        HttpURLConnection conn = super.createConnection(url);
        conn.setRequestProperty("User-Agent", "");
        return conn;
    }
}

Ответ 2

Я никогда не пользовался Universal Image Loader, но за последние несколько недель была выпущена пара действительно хороших альтернатив. Возможно, они заслуживают внимания.

Первый - это Volley, новая сетевая библиотека Google, объявленная на I/O 2013 https://developers.google.com/events/io/sessions/325304728

Второй - это площадь Пикассо. Команда Square делает отличную работу с их файлами Android. http://corner.squareup.com/2013/05/picasso-one-dot-oh.html