0Pricing
Android Academy · Lección

Carga de imágenes con Coil

Carga asíncrona de imágenes en Compose

Carga de imágenes con Coil es una lección gratuita de Android Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Android Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Android Academy incluye 4 lecciones en total.

Por qué necesita un cargador de imágenes

La mayoría de las aplicaciones modernas muestran imágenes de Internet: fotos de perfil, imágenes de productos y miniaturas de artículos. Descargar y descodificar esas imágenes correctamente es más difícil de lo que parece.

Debe obtener los bytes a través de la red en un subproceso en segundo plano, descodificarlos en un bitmap, almacenarlos en caché para no volver a descargarlos y cancelar la solicitud si el usuario se desplaza. Hacerlo manualmente puede provocar errores.

Coil (Coroutine Image Loader) se encarga de todo esto mediante una API pequeña y compatible con Compose. En esta lección cargará su primera imagen remota.

Añadir Coil al proyecto

Coil se distribuye como una dependencia de Gradle. Para Jetpack Compose necesita el artefacto coil-compose, que proporciona el composable AsyncImage.

Añádalo al build.gradle.kts de su módulo. Coil 3 es la versión principal actual y funciona en varias plataformas; aquí usaremos la integración con Compose.

// build.gradle.kts (module level)
dependencies {
    implementation("io.coil-kt.coil3:coil-compose:3.0.4")
    implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.4")
}

Permiso de Internet

Para descargar imágenes desde una URL, su aplicación necesita el permiso INTERNET. Es un permiso normal, concedido durante la instalación, por lo que solo debe declararlo en el manifiesto. No se muestra ninguna solicitud durante la ejecución.

Sin este permiso, todas las solicitudes de red fallan con una excepción de seguridad.

<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />
    <application ...>
        ...
    </application>
</manifest>

Su primer AsyncImage

La forma más sencilla de mostrar una imagen remota en Compose es AsyncImage. Proporciónele un model (normalmente una cadena con una URL) y un contentDescription, y Coil se encargará del resto: obtenerla en segundo plano, descodificarla y mostrarla.

Usa automáticamente corrutinas vinculadas a la composición, por lo que la solicitud se cancela si el composable abandona la pantalla.

import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun Avatar() {
    AsyncImage(
        model = "https://example.com/avatar.png",
        contentDescription = "User avatar",
        modifier = Modifier.size(96.dp)
    )
}

contentScale: cómo se ajusta la imagen

Rara vez las imágenes coinciden exactamente con el tamaño del espacio disponible en el diseño. ContentScale controla cómo se escala el bitmap dentro de sus límites.

  • ContentScale.Crop rellena el cuadro y recorta el contenido sobrante (ideal para avatares y miniaturas).
  • ContentScale.Fit mantiene visible la imagen completa, aunque puede dejar espacio vacío.
  • ContentScale.FillBounds estira la imagen para rellenar el espacio (puede distorsionarla).

Crop es la opción más habitual para espacios de tamaño fijo.

import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun CircleAvatar(url: String) {
    AsyncImage(
        model = url,
        contentDescription = "Avatar",
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(80.dp)
            .clip(CircleShape)
    )
}

Crear una solicitud con ImageRequest

Pasar una cadena con una URL es la opción rápida. Para tener más control, cree un ImageRequest. Esto le permite configurar opciones como la transición gradual, las cabeceras, las transformaciones y las claves de caché.

Necesita un Context, que Compose proporciona mediante LocalContext.current.

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade

@Composable
fun ProductImage(url: String) {
    val context = LocalContext.current
    val request = ImageRequest.Builder(context)
        .data(url)
        .crossfade(true)
        .build()

    AsyncImage(
        model = request,
        contentDescription = "Product photo"
    )
}

Transición gradual para cargas suaves

De forma predeterminada, una imagen aparece instantáneamente cuando termina de cargarse, lo que puede resultar brusco. crossfade(true) hace que la imagen aparezca gradualmente mediante una animación breve.

También puede indicar una duración en milisegundos para que la transición sea más lenta o rápida. Este pequeño detalle hace que las listas resulten mucho más cuidadas.

import coil3.request.ImageRequest
import coil3.request.crossfade
import android.content.Context

fun smoothRequest(context: Context, url: String) =
    ImageRequest.Builder(context)
        .data(url)
        .crossfade(durationMillis = 300)
        .build()

Cargar desde distintas fuentes

El model de AsyncImage es flexible. Coil puede cargar imágenes desde muchos tipos de fuente, no solo desde URL remotas:

  • Un String o un Uri para archivos de red o locales.
  • El identificador de un recurso drawable (R.drawable.logo).
  • Un File del dispositivo.
  • Un Uri de contenido procedente del selector de fotos.

Esto permite que el mismo composable gestione imágenes remotas y locales sin diferencias apreciables.

import android.net.Uri
import androidx.compose.runtime.Composable
import coil3.compose.AsyncImage

@Composable
fun FlexibleImage(source: Any) {
    // source can be a URL String, a Uri, a File, or a resource id
    AsyncImage(
        model = source,
        contentDescription = null
    )
}

// Examples:
// FlexibleImage("https://example.com/pic.jpg")
// FlexibleImage(Uri.parse("content://media/external/images/1"))

Reaccionar al estado de carga

A veces necesita saber si la imagen se está cargando, se ha cargado correctamente o ha fallado para mostrar una interfaz distinta en cada caso. AsyncImagePainter expone ese estado, pero el enfoque más sencillo es SubcomposeAsyncImage, que permite proporcionar contenido para cada estado.

En la próxima lección profundizaremos en los marcadores de posición; aquí verá la estructura básica de una carga consciente del estado.

import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import coil3.compose.SubcomposeAsyncImage

@Composable
fun StatefulImage(url: String) {
    SubcomposeAsyncImage(
        model = url,
        contentDescription = "Photo",
        loading = { CircularProgressIndicator() }
    )
}

La cancelación viene incluida

Una de las mayores ventajas de Coil es la cancelación automática. Como AsyncImage inicia su solicitud dentro de la composición, cuando el composable abandona la pantalla (por ejemplo, cuando una fila sale de un LazyColumn al desplazarse), la solicitud en curso se cancela.

Esto ahorra ancho de banda y CPU, y evita trabajo innecesario. No tiene que escribir código de cancelación, por eso Coil funciona tan bien en listas largas.

import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun PhotoFeed(urls: List<String>) {
    LazyColumn {
        items(urls) { url ->
            AsyncImage(
                model = url,
                contentDescription = null,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
            )
        }
    }
}

Una tarjeta de imagen completa

Combinemos lo aprendido: una tarjeta con una imagen remota que rellena la parte superior, usa una transición gradual y recorta la imagen a una altura fija. Este es el patrón básico que reutilizará constantemente.

import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade

@Composable
fun ImageCard(title: String, imageUrl: String) {
    val context = LocalContext.current
    Card(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
        Column {
            AsyncImage(
                model = ImageRequest.Builder(context)
                    .data(imageUrl)
                    .crossfade(true)
                    .build(),
                contentDescription = title,
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxWidth().height(180.dp)
            )
            Text(text = title, modifier = Modifier.padding(16.dp))
        }
    }
}

Comprobación rápida

¿Qué composable de coil-compose es la forma más sencilla de mostrar una imagen remota mediante una URL en Jetpack Compose?

Repaso

Ha cargado sus primeras imágenes remotas con Coil. Estas son las ideas clave:

  • Añada coil-compose y una dependencia de red de OkHttp, además del permiso INTERNET.
  • AsyncImage(model = url, contentDescription = ...) es la opción rápida.
  • Use ContentScale.Crop con un tamaño fijo para avatares y miniaturas.
  • Cree un ImageRequest para usar una transición gradual y obtener más control.
  • Coil cancela automáticamente las solicitudes en curso cuando los composables abandonan la pantalla.

Siguiente: hacer que la carga sea más fluida con marcadores de posición y estados de error.

Preguntas frecuentes

¿La lección «Carga de imágenes con Coil» es gratis?

Sí — el texto completo de «Carga de imágenes con Coil» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Android Academy, actualiza a CoddyKit PRO. El curso de Android Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Carga de imágenes con Coil»?

Carga asíncrona de imágenes en Compose Practicas Android Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Android Academy?

No se requiere experiencia previa. Android Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «Carga de imágenes con Coil»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Android Academy?

Sí. Cada lección de Android Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Carga de imágenes con Coil
  2. Marcadores de posición y estados de error
  3. Caché y rendimiento
  4. Reproducción de audio y vídeo
← Volver a Android Academy