Я думаю, каждый из нас сталкивается с загрузкой изображений по URL. Самый простой способ решения этой задачи: использовать готовую стороннюю библиотеку. Как правило, одним из таких готовых решений оказывается Universal Image Loader (UIL), Picasso. Когда я спрашиваю у разработчика, почему он выбрал ту или иную библиотеку, то, как правило, получаю разные ответы. Например, «у Picasso/UIL нет проблем с memory leaks», или «Square делают только правильные вещи», или просто «Да вот использую UIL, работает – и хорошо».
Так вот, мне стало интересно: какая из этих 2-х библиотек оптимально использует память? Я использую UIL и имею проблему с OutOfMemory на старых устройствах. Возможно, Picasso это лекарство?
Так появилась идея этого benchmark-а.
Цель тестирования: определить, какая из библиотек (UIL или Picasso) минимально использует память устройства.
Тест кейсы:
— Загрузка маленьких изображений (240х240)
— Загрузка больших изображений (>400px по любому из габаритов)
— Загрузка больших изображений и преобразование их размера к габаритам ImageView
— Загрузка маленьких изображений и их показ в виде круглой картинки
— Загрузка больших изображений и показ их в конфигурации RGB565
Методика выполнения теста:
В качестве списка используем GridView шириной в 2 столбца. Адаптер настраивается отдельно под каждый тест кейс. В адаптер отдаем список заранее подготовленных URL, создавая, таким образом, одинаковые условия тестирования.
С периодом в 1 сек, список автоматически делает один проход вниз, а потом вверх с шагом в 4 изображения. По каждому шагу производится измерение памяти, использованной приложением.
Измеряем использованную память в 3 этапа для каждого тест кейса:
— первый запуск — с чистым кешем приложения;
— второй запуск: не закрывая приложение после первого прохода;
— третий запуск – после повторного открытия приложения без чистки кеша.
По окончанию выполнения тест кейса, я дополнительно записывал размер кеша, что тоже немаловажно для старых устройств.
Исходники Benchmark-а можно найти по ссылке
http://ift.tt/1ikFS1D. Проект собран под Gradle.
Итак, ниже результаты по каждому тест кейсу. Ось Y – используемая приложением память в Мб. Ось Х – время проведения тест кейса.
Загрузка маленьких изображений
Размер кеша: Picasso=1.39 Мб, UIL=1.17 Мб
Загрузка больших изображений
Размер кеша: Picasso=3,67 Мб, UIL=5,44 Мб
Загрузка больших изображений с преобразованием до размера ImageView
Размер кеша: Picasso=3,67 Мб, UIL=5,44 Мб
Загрузка маленьких изображений и их обрезка до круглой картинки
Размер кеша: Picasso=1.39 Мб, UIL=1.17 Мб
Загрузка больших изображений и показ их в конфигурации RGB565
Результаты экспериментов с большими картинками меня впечатлили, и я решил, что стоит попробовать настроить конфигурацию UIL. Чтобы не сильно загружать память кешем – я попробовал отключить у UIL кеш в RAM. И, как вариант, установить кешируемый габарит картинки – не более, чем в половину экрана.
На основе эксперимента я сделал следующие выводы:
- Если ваши списки работают с маленькими изображениями (сравнимыми с размером ImageView) – выбор библиотеки для вас не принципиален. Picasso создает чуть больший кеш на диске, при этом используя меньше RAM примерно на тот же размер.
- Picasso показала потрясающие результаты по управлению памятью, работая с большими изображениями. UIL, по всей видимости, хранит оригинал изображения в памяти. Picasso хранит уже преобразованный размер картинки. Потому и кеш на диске у Picasso значительно меньше.
- UIL может работать с той же эффективностью, что и Picasso, если его дополнительно настроить. Например, ограничить размер кеша в памяти. Или, как в одном из тестов – ограничить вручную размер кешируемых фотографий. Второй способ может быть непригоден для использования, поскольку устанавливает глобальную конфигурацию ImageLoader-а.
- Работа с круглыми аватарами обходится «дешевле» через Picasso. Но, опять же, за счет того, что я вручную вызывал recycle() у оригинального Bitmap-а. Такое же действие можно выполнить и в UIL, устанавливая переопределенный BitmapDisplayer.
- Picasso предельно проста в использовании и уже «с коробки» работает с памятью эффективно. Так выглядит инициализация и выполнение загрузки для библиотек:Picasso
public class PicassoSquareFitAdapter extends BaseBenchmarkAdapter {
public PicassoSquareFitAdapter(Context context, IUrlListContainer urlListContainer) {
super(context, urlListContainer);
}
@Override
protected void loadImage(ImageView imageView, String url) {
Picasso.with(context).load(url).fit().into(imageView);
}
}UILpublic class UILSquareFitAdapter extends BaseBenchmarkAdapter {
private DisplayImageOptions options;
public UILSquareFitAdapter(Context context, IUrlListContainer urlListContainer) {
super(context, urlListContainer);
ImageLoaderConfiguration config = ImageLoaderConfiguration.createDefault(context);
ImageLoader.getInstance().init(config);
options = new DisplayImageOptions.Builder()
.imageScaleType(ImageScaleType.EXACTLY)
.resetViewBeforeLoading(true)
.cacheInMemory(true)
.cacheOnDisc(true)
.build();
}
@Override
protected void loadImage(ImageView imageView, String url) {
ImageLoader.getInstance().displayImage(url, imageView, options);
}
}
- Есть у Picasso и минус: трансформации изображений и приведение к RGB565 необходимо делать в самописных классах.RoundTransformation
public class RoundTransformation implements Transformation {
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
float radius = size / 2f;
canvas.drawCircle(radius, radius, radius, paint);
squaredBitmap.recycle();
return bitmap;
}
@Override
public String key() {
return "circle";
}
}Config565Transformationpublic class Config565Transformation implements Transformation {
@Override
public Bitmap transform(Bitmap source) {
Bitmap resultBitmap = Bitmap.createBitmap( source.getWidth(), source.getHeight(), Bitmap.Config.RGB_565 );
Canvas canvas = new Canvas(resultBitmap);
Paint paint = new Paint();
paint.setFilterBitmap(true);
canvas.drawBitmap(source, 0, 0, paint);
source.recycle();
return resultBitmap;
}
@Override
public String key() {
return "Config565Transformation";
}
}
Для себя я сделал вывод: проекты необходимо переводить на Picasso. В моем случае это решит проблему с перерасходом памяти. Надеюсь, этот пост будет полезен и Вам!
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий