Универсальный загрузчик изображений не может загружать изображения иногда
Я использую универсальный загрузчик изображений, и я получаю довольно большое количество изображений, которые не загружаются для пользователей каждый день.
Я использую этот код, чтобы получить мои ошибки в аналитике.
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