Как стать автором
Обновить

Комментарии 28

Отличное сравнение.
Для загрузки картинок под Android есть еще библиотека glide (https://github.com/bumptech/glide).
Интересно, насколько она эффективна по сравнению с Picasso.
Допишу на выходных тесты этих 2-х либ. Зафейворите репозиторий — выложу отчет туда.
А как у перечисленных библиотек с такими функциям/проблемами:

1. Картинка грузится с закрытого сервера, требуется авторизация, кроме того с запросом передаются специальные HTTP-заголовки, также как и с ответом — и всё это надо гибко обработать

2. Картинка грузится медленно, приложение должно быть возможно свернуть/восстановить (короче, есть ли там работа в режиме фонового service-а)?
1. С UIL-ом такая комбинация точно работает. В конфигурации можно установить кастомный ImageDownloader, который экстендит библиотечный. Там и можно настроить хедеры и выполнить авторизацию перед запросом. Я использую в одном проекте. А вот с Picasso — не уверен, нужно смотреть.
2. Нужно тестировать. Но, поскольку, библиотека использует пул потоков для загрузки — то скорее всего Threads никуда не деваются при сворачивании Activity. А если нужно остановить\восстановить запросы по onStart()/onPause() — обе библиотеки поддерживают такую возможность.
Я использую UIL для загрузки картинок в твиттер клиенте Robird.
Каждый твит имеет как минимум 1 картинку — аватарку пользователя и может еще отображать превью картинок с разных сервисов.
UIL работает очень плавно и быстро подгружает картинки. Никаких поддергиваний при скроле. Вот моя конфигурация:

        Executor downloadExecutor = Executors.newFixedThreadPool(5);
        Executor cachedExecutor = Executors.newSingleThreadExecutor();

        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        int memClass = am.getMemoryClass();
        final int memoryCacheSize = 1024 * 1024 * memClass / 8;

        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showStubImage(android.R.color.transparent)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
                .cacheInMemory(true)
                .cacheOnDisc(true)
                .build();

        File cacheDir = StorageUtils.getCacheDirectory(this);
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
                .taskExecutor(downloadExecutor)
                .taskExecutorForCachedImages(cachedExecutor)
                .memoryCache(new UsingFreqLimitedMemoryCache(memoryCacheSize)) // 2 Mb
                .discCache(new TotalSizeLimitedDiscCache(cacheDir, 52428800))
                .imageDownloader(new BaseImageDownloader(this, 5 * 1000, 30 * 1000)) // connectTimeout (5 s), readTimeout (30 s)
                .defaultDisplayImageOptions(options)
                .build();



К сожалению при использовании Picasso у меня были проблемы со скоростью загрузки картинок. Правда это было в первых версия библиотеки. Как она сейчас работает в плане скорости загрузки и отображения картинок?
А почему именно такой объем памяти?
int memClass = am.getMemoryClass();
final int memoryCacheSize = 1024 * 1024 * memClass / 8;


memClass / 8 — почему именно этот коэффициент?
Всегда волновал вопрос, как правильнее высчитать размер кеша.
Коэффициент был выбран опытным путем. Picasso использует коэффициент равный 7. Вроде и у них и у меня все ок с этим)
developer.android.com/training/displaying-bitmaps/cache-bitmap.html#memory-cache
Note: In this example, one eighth of the application memory is allocated for our cache. On a normal/hdpi device this is a minimum of around 4MB (32/8). A full screen GridView filled with images on a device with 800x480 resolution would use around 1.5MB (800*480*4 bytes), so this would cache a minimum of around 2.5 pages of images in memory.
Есть идея, как кодом вычислить «подергивания»? Если что — реализую, и будет ещё один Benchmark.
Поддергивания только в реальном использовании можно заметить. Бенчмаркам не поддается))

У вас в реальных проектах picasso используется? есть списки с картинками?
Пока что UIL. На тест Picasso подтолкнула постоянная проблема с бесконечной сборкой мусора и OutOfMemory на старых устройствах. Но планирую пробу заинтегрить Picasso.
я планирую отказаться от UIL из-за крешей последней версии на android 4.3 при попытке загрузить много картинок.
Хотелось бы еще оптимизировать использование памяти, вот присматриваюсь к Picasso и Glide.
Еще как я понял загрузку картинок при скроле нельзя тормозить в picasso?
можно вот так: Настройки > Для разработчиков > Запись времени работы GPU
Еще было бы интересно увидеть в тестировании volley
На выходных добавятся ещё 3 библиотеки. Выпущу benchmark v2.
В UIL есть еще баг который приводит к кешированию картинок 2 раза.

Все потому, что используют размер вью в качестве ключа для кеша, и если у вас ImageView, например, match_parent/wrap_content, то в первый проход размер не будет известен, а будет только во второй, как результат, получаем:
1. дублирующиеся картинки в памяти (и на диске?)
2. и бонусом мигание картинок при прокрутке.

p.s. баг тикет на github issues/376
Дублированиения на диске нет. Дублирование в памяти можно предотвратить с помощью опции конфигурации ImageLoaderConfiguration.denyCacheImageMultipleSizesInMemory().

А проблема с первым проходом при match_parent/wrap_content — да, существует. На данный момент выход — это вызывать ImageLoader через post():
imageView.post(new Runnable() {
    @Override
    public void run() {
        imageLoader.displayImage(...);
    }
});
Я для себя сделал грязный хак, который решает все эти проблемы разом:

/* com.nostra13.universalimageloader.core.ImageLoader:194 */
String memoryCacheKey = uri; // MemoryCacheUtil.generateKey(uri, targetSize);

Не очень красиво, за то эффективно. Но будет здорово, если можно будет это решить как то в конфигурации по умолчанию, без лишних движений.
Да, возможность конфигурить извне memoryCacheKey (типа MemoryCacheKeyGenarator) — это в ближайших планах.
по поводу post runnable

Ну вот у нас есть сетка с картинками, видно сразу 20+ картинок, то есть мне нужно запостить 20 runnable просто что бы подождать пока будет известен размер для ImageView? А потом мне что нужно хранить флаг, и больше это не делать, или каждый раз при прокрутке пулять 20 + runnable?
Как то это все не правильно.
Да, пока это такой workaround. Хорошего решения, встроенного в текущую логику библиотеки, я пока не придумал.
В документации по UIL написано, что порядок определения размеров Bitmap следующий:

  • Get actual measured width and height of ImageView
  • Get android:layout_width and android:layout_height parameters
  • Get android:maxWidth and/or android:maxHeight parameters
  • Get maximum width and/or height parameters from configuration (memoryCacheExtraOptions(int, int) option)
  • Get width and/or height of device screen

Соответственно, если размеры ImageView, в который нужно положить изображение, никак не ограничить (match_parent/wrap_content не в счет), произойдет загрузка изображения, смасштабированного под ширину/высоту устройства. Я для себя проблему расчета размера Bitmap'ов при загрузке оных в GridView решил установкой параметров maxWidth/maxHeight, принадлежащих отдельным ImageView, в нужные мне значения.
Вообще это какой то не правильный подход. Зачем ограничивать размеры вью? Что бы потом изобретать велосипед с ручным расчетом на разных размерах экранов? Для этого и придуман wrap_content/match_parent/ layout_weight.

Все что написано вами выше, должно быть опционально и выключено по умолчанию. Потому что, большинство рест апи позволяет:
1. тянуть картинки разного качества, а это значит что нам не нужно дополнительно, что либо еще делать на клиентах. Экономим память, диск, сеть, батарейку и тд.
2. ImageView, без труда может и сам масштабировать картинку, если нужно.

Итого, самый популярный способ показать картинки: GridView с автоматическим расположением картинок (количество столбцов, размер и тд), и uil тут явно не ваш друг.
У меня опыта разработки под Android всего два месяца, поэтому могу порой принимать странные решения. :) Спасибо за объяснение, посмотрю в сторону Picasso и других библиотек.
Кстати, какие версии библиотек использовались в бенчмарке? Это важно.
из build.gradle:
compile 'com.squareup.picasso:picasso:2.1.1@jar'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.0@jar'
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории