March 11, 2012

#4 - Universal Image Loader. Часть 1 - Введение [RU+EN]

English version - "Universal Image Loader. Part 1 - Introduction"

    При разработке приложений под Android довольно часто можно столкнуться с задачей отображения некоего графического контента из интернета. Поэтому снова и снова приходится  обеспечивать загрузку изображений из сети, их обработку и отображение в условиях ограниченности оперативной памяти. И несмотря на однородность задачи каждый новый проект накладывает на задачу свои специфические требования: возможно нужно организовать кэширование загруженных картинок; если картинки довольно большие, то необходимо обеспечить эффективную работу с памятью для предотвращения злополучной ошибки OutOfMemoryError; возможно во время загрузки изображения нужно показывать картинку-заглушку; а может одну и ту же картинку надо будет отображать в разных размерных вариациях; и т.д. В результате тратятся время и ресурсы на адаптацию программного кода под специфические нужды. Именно данная проблематика и подтолкнула меня к созданию библиотеки с открытым исходным кодом - Universal Image Loader, целью которой является универсализация решения вышеописанной задачи в виде гибкого и конфигурируемого инструмента.
    На данный момент библиотеку можно использовать повсеместно, где надо загрузить и отобразить (и возможно ещё закэшировать) картинку из интернета или из файловой системы смартфона. Классические примеры возможности применения ImageLoader'а - это списки, таблицы, галереи, где необходимо отображать изображения из сети.

    Главные фишки ImageLoader'а:
  • асинхронная загрузка и отображение изображений из интернета или с SD-карты;
  • возможность кэширования загруженных картинок в памяти и/или на файловой системе устройства;
  • возможность отслеживания процесса загрузки посредством "слушателей"
  • эффективная работа с памятью при кэшировании картинок в памяти;
  • широкие возможности настройки инструмента под свои нужды.
    Что же можно настраивать в ImageLoader'e?

    Глобальные настройки:
  • максимальный размер кэшируемых в памяти картинок;
  • тайм-аут для установки соединения и загрузки картинки;
  • максимальное количество потоков для загрузки изображений, работающих одновременно;
  • приоритет потоков по загрузке и отображению картинок;
  • программная реализация дискового кэша (можно выбрать одну из готовых реализаций или создать свою собственную);
  • программная реализация кэша в памяти (можно выбрать одну из готовых реализаций или создать свою собственную);
  • опции загрузки изображения по умолчанию
    Опции загрузки изображения (применяются к каждому отдельному вызову ImageLoader.displayImage(...)) предоставляют возможность указать:
  • отображать ли картинку-"заглушку" в ImageView, пока реальная картинка грузится? (если да, то нужно указать эту "заглушку");
  • отображать ли какую-либо картинку в ImageView, если URL картинки был передан пустым? (если да, то нужно указать эту картинку); 
  • кэшировать ли загруженную картинку в памяти?
  • кэшировать ли загруженную картинку на файловой системе?
  • тип декодирования изображения (максимально быстрый или максимально экономный для памяти).
    Как уже упоминалось, программные реализации дискового кэша и кэша в памяти можно подсунуть свои. Но скорее всего вам будет достаточно готовых решений, которые в большинстве своем представляют собой кэши, ограниченные по какому-либо параметру (размер, количество файлов) и имеющие свою логику самоочищения при превышении лимита (FIFO, самый старый объект, самый большой объект, наиболее редко используемый).

    Возможностей конфигурирования достаточно, но это не тот случай, наподобие "главного принципа UNIX": "Вы можете сконфигурировать ВСЁ. И вы БУДЕТЕ  конфигурировать все." :) В случае ImageLoader'а, вы можете настраивать все, но это отнюдь не обязательно: конфигурация по умолчанию всегда доступна и подходит для большинства случаев.

    Особенности реализации
    Немного слов о структуре проекта. Каждая задача на загрузку и отображение картинки (а это, забегая вперед, вызов ImageLoader.displayImage(imageView, imageUrl)) выполняется в отдельном потоке, кроме случаев, если картинка находится в кэше в памяти - тогда она просто сразу отображается. Существует отдельная очередь потоков, куда попадают задачи, если нужная картинка закэширована на файловой системе. Если же нужной картинки нет в кэше, то задача-поток попадает в пул потоков. Т.о. быстрому отображению закэшированных картинок ничего не препятствует.
    Алгоритм обработки задачи упрощенно представлен на схеме:



    Можно условно выделить основные действующие лица в проекте:
  • вышеупомянутые очередь и пул потоков;
  • кэш в памяти;
  • дисковый кэш;
  • декодер изображений, который перегоняет файлы картинок в объекты Bitmap.
А управляет всем этим главный класс ImageLoader, через который и происходит основное взаимодействие с пользователем.
    В следующей части Я расскажу непосредственно о Universal Image Loader API, а также дам некоторые советы и рекомендации по использованию библиотеки.

Следующие статьи:
Исходники проекта доступны здесь.

20 comments:

  1. Anonymous5/6/12 14:35

    Здравствуйте Сергей! Как с Вами можно связаться? есть вопросы. Спасибо

    ReplyDelete
    Replies
    1. Здравствуйте. На GitHub есть мой email - вот здесь

      Delete
  2. Anonymous29/1/13 00:34

    Молодьцы! Еще не юзал, но по статьям это то, что мне нужно.

    ReplyDelete
  3. Anonymous9/2/13 12:49

    Спасибо. Хорошая библиотека. Не подскажите каким образом можно сделать автоматическое слайдшоу? В каком направлении "копать"?

    ReplyDelete
    Replies
    1. ViewPager и Timer вам в руки.

      Delete
  4. Anonymous9/2/13 14:10

    Спасибо. Я к этому же и пришел))

    ReplyDelete
  5. Пытаюсь использовать вместе с facebook api и выдает гору ошибок, может подскажете в чем моя ошибка?

    ReplyDelete
    Replies
    1. Извините, но что-то меня подводят мои экстрасенсорные способности в последнее время. Так что не смогу помочь.

      Delete
  6. Anonymous19/3/13 08:42

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

    ReplyDelete
    Replies
    1. UIL не предоставляет функциональность масштабирования. Для этого вам нужно дополнительно использовать другие библиотеки (PhotoView, ImageViewTouch, gesture-image-view, ...). Также надо будет указать UIL, чтобы он не уменьшал картинки при декодировании: в опциях .imageScaleType(ImageScaleType.NONE).

      Delete
  7. Anonymous21/3/13 15:09

    Здравствуйте, отличная библиотека, спасибо! А не подскажите как можно добавить функциональность double-click zoom?

    ReplyDelete
    Replies
    1. Для этого надо использовать сторонние библиотеки: PhotoView, ImageViewTouch, gesture-image-view,...

      http://stackoverflow.com/questions/13398288/image-zoom-issue-with-universal-image-loader-and-view-pager

      Delete
  8. Отличная библиотека, спасибо! а можно URI с Drawable использовать?

    ReplyDelete
  9. Добрый день, огромное спасибо за библиотеку!
    Вопрос: предпочтительнее изображения использовать из assets нежели из drawable я так понимаю ?

    ReplyDelete
    Replies
    1. Добрый. Да, лучше. А почему не использовать ImageView.setImageResource(...)?

      Delete
  10. И как можно сделать донат, не юзая пэйпал ? )

    ReplyDelete
  11. Anonymous10/4/13 03:14

    Где не искал, не нашел самого просто примера : как отобразить картинку из урла в ImageView.. помогите пожалуйста !

    ReplyDelete
    Replies
    1. Anonymous10/4/13 03:21

      Все круто.. я был пьян и было поздно.. Спасибо Вам за прекрасный труд !

      Delete