Сегодня сложно найти Android-приложение совсем без картинок: аватарки, баннеры и иконки должны загружаться быстро и не тормозить интерфейс. Picasso — это библиотека от компании Square, которая берёт на себя всю грязную работу: скачивание, кэширование, изменение размеров и показ изображений в одну строчку кода. В этом руководстве я покажу, как использовать picasso kotlin в реальном проекте — от подключения зависимости до обработки ошибок и плавной прокрутки списков.
Коротко о библиотеке
Square разработала Picasso как минималистичный инструмент для загрузки картинок. Он добавляет к APK около 121 КБ и содержит примерно 849 методов — очень легковесный по сравнению с аналогами. Библиотека автоматически кэширует изображения в оперативной памяти и на диске, корректно обрабатывает переиспользование View в списках и позволяет трансформировать картинки на лету. Для простых приложений, где не нужна анимация GIF или сверхсложные трансформации, Picasso остаётся отличным выбором даже в 2026 году.
Подключение к проекту
Первым делом добавляем зависимость в build.gradle.kts модуля app. Если используете Groovy-синтаксис, запись будет немного другой, но смысл тот же.
dependencies {
implementation("com.squareup.picasso:picasso:2.8")
}
После синхронизации Gradle не забудьте прописать разрешение на интернет в AndroidManifest.xml, иначе загрузка изображений будет падать с ошибкой.
<uses-permission android:name="android.permission.INTERNET" />
Простейший пример загрузки
Чтобы загрузить изображение по URL и отобразить его в ImageView, достаточно одной строчки. Библиотека сама запустит фоновый поток, скачает картинку, сохранит в кэш и покажет результат.
Picasso.get()
.load("https://example.com/photo.jpg")
.into(imageView)
Этот код можно разместить прямо в onCreate Activity. Никакой ручной работы с потоками, никаких дополнительных настроек — всё происходит само.
Placeholder и обработка ошибок
Пока изображение загружается, полезно показать заглушку, чтобы экран не выглядел пустым. Если загрузка провалилась, пользователь тоже должен видеть какое-то изображение, а не пустое место. Для этого у Picasso есть методы placeholder и error.
Picasso.get()
.load("https://example.com/photo.jpg")
.placeholder(R.drawable.ic_placeholder)
.error(R.drawable.ic_error)
.into(imageView)
Если нужно получить доступ к загруженному Bitmap напрямую, используйте интерфейс Target. Это пригодится, когда картинку надо сохранить локально или передать в другой компонент.
Picasso.get()
.load(url)
.into(object : Target {
override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {
imageView.setImageBitmap(bitmap)
}
override fun onPrepareLoad(placeHolderDrawable: Drawable?) {}
override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) {}
})
Второй параметр Picasso.LoadedFrom подскажет, откуда взялась картинка: из памяти, с диска или из сети.
Изменение размера и обрезка
Если загружать на слабый телефон огромное фото с сервера, приложение может упасть с OutOfMemoryError. Чтобы избежать этого, указывайте конкретные размеры через resize и выбирайте способ масштабирования: centerCrop или centerInside.
Picasso.get()
.load("https://example.com/large.jpg")
.resize(800, 600)
.centerCrop()
.into(imageView)
Это особенно важно для изображений, которые занимают небольшую область на экране, а приходят в оригинальном разрешении на несколько мегапикселей.
Работа с RecyclerView
В списках, где View переиспользуются, старая загрузка может наложиться на новую. Picasso умеет автоматически отменять запрос к ImageView, если тот был переиспользован для другого элемента. Никакого дополнительного кода не требуется — просто вызывайте load().into() в методе адаптера.
Однако если вам нужна более продвинутая логика вроде паузы загрузки во время быстрой прокрутки, можно подключить PicassoScrollListener и управлять тегами вручную. Но для большинства сценариев достаточно стандартного поведения «из коробки».
Трансформации изображений
Picasso позволяет трансформировать изображение перед показом: скруглить углы, сделать чёрно-белым, наложить фильтр. Для этого используется абстрактный класс Transformation, который нужно реализовать.
class CircleTransform : Transformation {
override fun transform(source: Bitmap): Bitmap {
val size = minOf(source.width, source.height)
val squaredBitmap = Bitmap.createBitmap(source, 0, 0, size, size)
if (squaredBitmap != source) source.recycle()
val bitmap = Bitmap.createBitmap(size, size, source.config ?: Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
val paint = Paint().apply {
isAntiAlias = true
shader = BitmapShader(squaredBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
}
canvas.drawCircle(size / 2f, size / 2f, size / 2f, paint)
squaredBitmap.recycle()
return bitmap
}
override fun key(): String = "circle"
}
Picasso.get()
.load(url)
.transform(CircleTransform())
.into(imageView)
Метод key() возвращает уникальный строковый идентификатор трансформации. Он нужен для корректной работы кэша: если один и тот же URL загружается с разными трансформациями, Picasso должен различать результаты.
Управление кэшем
По умолчанию Picasso использует LRU-кэш в памяти (около 15% доступной оперативной памяти приложения) и дисковый кэш объёмом от 5 до 50 МБ в зависимости от свободного места на устройстве. В большинстве случаев этого достаточно, но иногда требуется ручное управление.
Если изображение на сервере обновилось, а Picasso продолжает показывать старую версию из кэша, помогает метод invalidate. А чтобы полностью запретить кэширование для конкретного запроса, используйте политики памяти и сети.
Picasso.get()
.load(url)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(imageView)
Злоупотреблять этим не стоит — каждая загрузка будет бить по трафику и батарее пользователя. Применяйте политики кэширования только для тех изображений, которые действительно часто обновляются.
Сравнение с другими библиотеками
В 2025-2026 годах основными конкурентами Picasso остаются Glide, Coil и Fresco. У каждой библиотеки своя ниша, и я собрал ключевые отличия в таблицу.
| Критерий | Picasso | Glide | Coil |
|---|---|---|---|
| Размер библиотеки | ~121 КБ, 849 методов | ~440 КБ, 2678 методов | ~2000 методов (легче Glide) |
| API | Минималистичный, легко освоить | Богатый, много настроек | Kotlin-ориентированный, поддержка корутин из коробки |
| Скорость загрузки | ~705 мс | ~676 мс | ~432 мс (лидер по скорости) |
| Поддержка GIF | Требует сторонних решений | Встроенная | Через coil-gif |
| Jetpack Compose | Только XML / View | Через accompanist или compose-адаптер | Нативная поддержка из коробки |
Если у вас проект на чистом Kotlin с Jetpack Compose, лучше сразу взять Coil. Если проект legacy-формата с XML-вёрсткой и вы цените простоту, Picasso будет отличным выбором. Glide подойдёт для больших приложений со сложными требованиями к трансформациям и анимациям.
Практическое задание
Чтобы закрепить навык, выполните простое упражнение: создайте приложение с полем ввода URL, кнопкой «Загрузить» и ImageView. При нажатии на кнопку вызывайте Picasso с введённым адресом, добавьте placeholder и сообщение в лог при ошибке. Затем попробуйте добавить список из пяти фотографий в RecyclerView и убедитесь, что прокрутка остаётся плавной. Это отнимет 20–30 минут, но даст полное понимание работы библиотеки на практике.
Коротко о главном
Picasso — это лёгкая и надёжная библиотека для загрузки изображений в Android на Kotlin. Она идеально подходит для простых и средних проектов, где не нужны анимации GIF и интеграция с Compose. Подключение занимает пару минут: добавили зависимость в Gradle, прописали INTERNET в манифесте и вызываете Picasso.get().load(url).into(imageView). Автоматическое кэширование, отмена запросов при переиспользовании View и встроенные трансформации делают Picasso проверенным инструментом, который будет работать даже через несколько лет. Освойте её сегодня — и загрузка картинок перестанет быть проблемой.