В предыдущей статье я сравнивал библиотеки UniversalImageLoader (UIL) и Picasso на предмет оптимального использования памяти. Среди комментариев были некоторые тонкости применения библиотек и просьбы протестировать другие загрузчики. Эти вопросы дали начало второй части benchmark-а с участием 5 библиотек.
Результаты:
Итак, в benchmark-е будут принимать участие библиотеки:
UIL, Picasso, Glide, Query, Volley
Исходники можно найти тут
В первой части статьи я проведу эксперименты с измерением используемой памяти с участием пяти библиотек.
Во второй части я сравню библиотеки по возможностям их настройки и визуальным характеристикам.
Используемая память
Если кому-то интересно ознакомиться с деталями эксперимента — их можно найти в предыдущей статье.
Скажу вкратце: я буду в равных условиях тестировать библиотеки для загрузки изображений и измерять используемую ими память. Графики на девайсе рисовались с помощью библиотеки GraphView.
Загрузка небольших изображений 240х240
В этом эксперименте можно отметить снижение расхода памяти у UIL благодаря хаку от автора библиотеки:
imageView.post(new Runnable() {
@Override
public void run() {
imageLoader.displayImage(...);
}
});
Загрузка больших изображений без конвертации формата
Весьма интересно ведет себя библиотека Query. Я не лазил в исходники, но у меня есть предположение, что кеш основан на списке, а не множестве. Иначе я не знаю как объяснить дублирование изображений на обратном пролистывании грида.
Так же неприятно удивила Volley. Очень часто не подгружается картинка в ImageView. Дебаг указал на то, что иногда производятся попытки установить recycled Bitmap. Вероятно, есть какая-то проблема с выбором подлежащих очистке картинок.
Загрузка больших изображений с конвертацией в формат RGB565 и подгонкой изображения к размеру ImageView
Как правило, от больших картинок не требуется 24-битный формат, в большинстве случаев достаточно и RGB565.
Наиболее просто сконвертировать формат позволяет UIL. Достаточно в опциях загрузки изображения указать необходимый Bitmap.Config. Для остальных библиотек конвертацию пришлось писать.
В этом эксперименте особо выделилась Glide, заняв памяти больше чем Volley, Query и Picasso вместе взятые. Сразу хочу уточнить: можно было ограничить размер кеша, но в эксперименте я хотел увидеть как библиотеки работают с памятью в базовой конфигурации. Каждая глобальная чистка по лимиту кеша — это заметный затык в работе UI-потока. Поэтому от библиотеки хотелось бы какой-то постепенной очистки, если так можно выразиться.
Загрузка маленьких изображений (240х240) с последующим скруглением
К сожалению, столь успешные результаты Volley учитывать нельзя, поскольку на обратном проходе я не увидел картинок. Все они оказались recycled, даже с учетом, что я не вызывал recycle() у оригинала при трансформации. Не годится.
Glide, судя по всему, выполняет преобразование всех картинок в RGB565, поскольку у картинок оказался черный фон вместо прозрачного. Не годится.
Наиболее просто делать трансформацию с помощью UIL и Query. В UIL есть встроенный класс RoundBitmapDisplayer, который можно подключить к опциям загрузки.
Для Query достаточно в опциях указать радиус скругления картинки.
Для Picasso и Glide включение трансформации в загрузку выглядит как один из этапов Builder-a.
Glide.load(url).centerCrop().transform(roundTransformation).into(imageView);
Picasso.with(context).load(url).transform(picassoRoundTransformation).noFade().into(imageView);
Для Volley пришлось переопределять ImageView и делать конвертацию Bitmap-a в методе setImageBitmap().
Если у кого есть решение лучше — предлагайте свои варианты.
Визуальные характеристики.
Picasso уступает остальным библиотекам в скорости загрузки изображений. Не знаю как это объяснить, но факт: картинки через Picasso появляются чуть позже.
Glide, как было сказано выше, преобразовывает картинки в RGB565, чем может доставить неприятности при трансформации изображений.
UIL визуально быстрее загружает картинки. Но нужно учесть одну особенность: при использовании FadeInBitmapDisplayer для плавного показа картинок, лучше использовать расширенный конструктор.
new FadeInBitmapDisplayer(duration, true, true, false)
В такой конфигурации картинка будет анимироваться только в первый раз (пока картика жива в кеше), и при пролистывании не будет напрягать взгляд излишней анимацией. Это ИМХО.
В Picasso эффект «fade in» работает по-определению именно в таком режиме.
Volley в свою очередь часто не показывает преобразованные изображения из-за того, что они уже recycled(). Жду в комментариях ваши предложения по исправлению этого бага.
Query визуально ничем не удивил. Загрузка картинок выглядит как-то прерывисто. Редко соблюдается тот порядок, в котором картинки были запрошены.
Настройка загрузчика
UIL — безусловный лидер по возможностям тонкой настройки параметров загрузки. Благодаря Builder-паттерну формирования настроек можно легко ознакомиться с возможностями библиотеки. В принципе, можно обойтись и без мануала. UIL так же позволяет подключить OnScollListener для приостановки запросов на время скролла списка.
Glide и Picasso — самые простые в интеграции библиотеки. Picasso имеет преимущество в наличии maven-репозитория. Если нужно быстро интегрировать загрузку изображений, при этом получив оптимальные настройки и экономный расход памяти — выбор за Picasso.
Picasso и UIL предоставляют интерфейсы, реализуя которые можно загрузить картинку куда угодно.
Volley требует долгой подготовки к использованию. Нужно самому создавать и конфигурировать экземпляр кеша и очередь загрузки. В разметке необходимо использовать виджет NetworkImageView или же его наследники. Для меня — это значительное неудобство. Единственный приемлемый вариант использования этой библиотеки для загрузки изображений — это если Network вашего проекта построен на Volley.
Query, в принципе, не тяжела в настройке. Но предлагаемый авторами вариант использования в адаптерах меня немного смущает. Для загрузки каждой картинки нужно создавать экземпляр класса AQuery, который сам по себе является довольно тяжелым. Это не лучшая библиотека, если хочется сэкономить процессорное время на сборке мусора.
AQuery aq = new AQuery(convertView);
ImageOptions options = new ImageOptions();
options.ratio = 1;
options.round = Integer.MAX_VALUE;
aq.id(imageView).image(url, options);
Нередко встречается необходимость использования своего HTTPClient-а для загрузки картинок. Volley и UIL предоставляют инструменты для настройки соединения. На просторах интернета я также встречал интеграцию кастомного HttpClient в Picasso. Но насколько я понял, стандартными средствами это сделать не получится.
Выводы
Чем больше библиотек — тем сложнее стало сделать какие-либо выводы. Попробую в одном предложении охарактеризовать каждую библиотеку.
Picasso — если нужно быстро интегрировать и не беспокоиться об используемой памяти
UIL — если Ваш проект требует специфическую настройку загрузки, но в то же время позволяет выполнить эту настройку быстро и понятно
Glide — некий клон Picasso (возможно, наоборот), но расходует немного больше памяти.
Volley — использование оправдано, если ваш Network построен на Volley, а соединение требует специфической настройки HttpClient-а для всего проекта
Query — сложная к пониманию и интеграции библиотека со слабой документацией, тем не менее показывающая отличные результаты по экономии памяти устройства.
Жду Ваших комментариев и полезных советов!
Автор: Artem_Manaenko