Glide/Coil для Kotlin: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Glide и Coil и зачем они нужны?

В современной Android-разработке загрузка и отображение изображений из сети, локальных файлов или ресурсов — одна из самых частых задач. Однако просто скачать картинку и показать её в ImageView недостаточно. Нужно учитывать множество нюансов: кэширование (чтобы не тратить трафик), обработка ошибок (если картинка не загрузилась), трансформации (круглые аватары, размытие), поддержка GIF и видео, а также плавная анимация появления.

Glide и Coil — это две самые популярные библиотеки для загрузки изображений в Kotlin/Android. Они решают все перечисленные проблемы «из коробки».

  • Glide — мощная, зрелая библиотека от Google (частично). Поддерживает GIF, видео, трансформации, анимации. Имеет огромное комьюнити.
  • Coil — более современная, лёгкая и написанная полностью на Kotlin с использованием корутин. Отлично интегрируется с Jetpack Compose.

В этой статье мы рассмотрим обе библиотеки, так как они решают одни и те же задачи, но разными способами. Вы сможете выбрать ту, которая лучше подходит под ваш проект.

Установка

Добавьте зависимости в файл build.gradle.kts (уровень модуля app):

Для Glide:

dependencies {
    implementation("com.github.bumptech.glide:glide:4.16.0")
    kapt("com.github.bumptech.glide:compiler:4.16.0") // для GlideApp
}

Для Coil:

dependencies {
    implementation("io.coil-kt:coil:2.6.0")
    // Если используете Compose:
    implementation("io.coil-kt:coil-compose:2.6.0")
}

После добавления синхронизируйте проект (Sync Now).

Быстрый старт

Давайте загрузим простую картинку из интернета в ImageView.

Пример с Glide:

// В Activity или Fragment
val imageView: ImageView = findViewById(R.id.my_image_view)
val url = "https://example.com/image.jpg"

Glide.with(this)
    .load(url)
    .into(imageView)

Пример с Coil:

// В Activity или Fragment
val imageView: ImageView = findViewById(R.id.my_image_view)
val url = "https://example.com/image.jpg"

imageView.load(url)

Как видите, Coil предлагает ещё более лаконичный синтаксис через extension-функцию load().

Основные методы и функции

Ниже приведены ключевые методы для работы с изображениями. Для каждого метода я покажу примеры для обеих библиотек.

1. load() — Загрузка изображения

Что делает: Основной метод, который принимает источник изображения (URL, URI, File, Drawable, Bitmap).

Параметры:

  • url: String — ссылка на изображение.
  • uri: Uri — локальный URI.
  • file: File — файл.
  • resourceId: Int — ID ресурса (R.drawable...).

Пример (Glide):

Glide.with(this)
    .load("https://example.com/photo.png")
    .into(imageView)

Пример (Coil):

imageView.load("https://example.com/photo.png")

2. placeholder() — Изображение-заглушка

Что делает: Показывает временную картинку, пока основное изображение загружается.

Параметры:

  • placeholder: Int — ID ресурса drawable.

Пример (Glide):

Glide.with(this)
    .load(url)
    .placeholder(R.drawable.ic_loading)
    .into(imageView)

Пример (Coil):

imageView.load(url) {
    placeholder(R.drawable.ic_loading)
}

3. error() — Изображение при ошибке

Что делает: Показывает картинку, если загрузка основного изображения не удалась (нет интернета, битый URL).

Параметры:

  • error: Int — ID ресурса drawable.

Пример (Glide):

Glide.with(this)
    .load(url)
    .error(R.drawable.ic_error)
    .into(imageView)

Пример (Coil):

imageView.load(url) {
    error(R.drawable.ic_error)
}

4. override() — Принудительный размер

Что делает: Изменяет размер изображения до указанных ширины и высоты (в пикселях). Полезно для экономии памяти.

Параметры:

  • width: Int — ширина.
  • height: Int — высота.

Пример (Glide):

Glide.with(this)
    .load(url)
    .override(300, 200)
    .into(imageView)

Пример (Coil):

imageView.load(url) {
    size(300, 200)
}

5. centerCrop() / fitCenter() — Масштабирование

Что делает: Определяет, как изображение будет вписано в ImageView.

  • centerCrop() — обрезает края, чтобы заполнить контейнер.
  • fitCenter() — вписывает целиком, возможно с пустыми полями.

Пример (Glide):

Glide.with(this)
    .load(url)
    .centerCrop()
    .into(imageView)

Пример (Coil):

imageView.load(url) {
    crossfade(true)
    transformations(CenterCrop())
}

6. circleCrop() — Круглая обрезка

Что делает: Превращает изображение в круг (идеально для аватарок).

Пример (Glide):

Glide.with(this)
    .load(url)
    .circleCrop()
    .into(imageView)

Пример (Coil):

imageView.load(url) {
    transformations(CircleCropTransformation())
}

7. skipMemoryCache() — Отключение кэша

Что делает: Запрещает кэширование изображения в оперативной памяти. Полезно для одноразовых картинок.

Параметры:

  • skip: Boolean — true, чтобы отключить кэш.

Пример (Glide):

Glide.with(this)
    .load(url)
    .skipMemoryCache(true)
    .into(imageView)

Пример (Coil):

imageView.load(url) {
    memoryCachePolicy(CachePolicy.DISABLED)
}

8. diskCacheStrategy() — Стратегия дискового кэша (только Glide)

Что делает: Управляет кэшированием на диске.

Параметры:

  • DiskCacheStrategy.ALL — кэшировать все версии.
  • DiskCacheStrategy.NONE — не кэшировать.
  • DiskCacheStrategy.DATA — только исходные данные.
  • DiskCacheStrategy.RESOURCE — только обработанные.

Пример (Glide):

Glide.with(this)
    .load(url)
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .into(imageView)

9. listener() — Отслеживание загрузки

Что делает: Позволяет реагировать на успешную загрузку или ошибку.

Пример (Glide):

Glide.with(this)
    .load(url)
    .listener(object : RequestListener<Drawable> {
        override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
            println("Ошибка загрузки: ${e?.message}")
            return false
        }

        override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
            println("Изображение загружено!")
            return false
        }
    })
    .into(imageView)

Пример (Coil):

imageView.load(url) {
    listener(
        onStart = { println("Загрузка началась") },
        onSuccess = { _, _ -> println("Успешно") },
        onError = { _, _ -> println("Ошибка") }
    )
}

10. crossfade() — Анимация появления

Что делает: Добавляет плавное появление изображения (fade-in).

Параметры:

  • duration: Int — длительность анимации в миллисекундах (по умолчанию 300).

Пример (Glide):

Glide.with(this)
    .load(url)
    .transition(DrawableTransitionOptions.withCrossFade(500))
    .into(imageView)

Пример (Coil):

imageView.load(url) {
    crossfade(true)
    // или crossfade(500) для кастомной длительности
}

Реальный практический пример

Представьте, что вы делаете приложение-галерею. Нужно загрузить список картинок из API и отобразить их в RecyclerView. Вот как это будет выглядеть с Coil (с Glide аналогично):

// Адаптер для RecyclerView
class ImageAdapter(private val imageUrls: List<String>) : RecyclerView.Adapter<ImageAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_image, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val url = imageUrls[position]
        holder.imageView.load(url) {
            placeholder(R.drawable.ic_loading)
            error(R.drawable.ic_error)
            crossfade(true)
            transformations(CenterCrop())
            size(400, 400)
        }
    }

    override fun getItemCount() = imageUrls.size

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val imageView: ImageView = itemView.findViewById(R.id.image_view)
    }
}

В этом примере мы:

  • Используем placeholder и error для UX.
  • Добавляем crossfade для плавности.
  • Применяем CenterCrop для единообразного вида.
  • Ограничиваем размер до 400x400, чтобы не перегружать память.

Советы и типичные ошибки

Советы:

Рекомендаций