0Pricing
Android Academy · Lección

Caché y rendimiento

Conceptos básicos de la caché en memoria y en disco

Caché y rendimiento es una lección gratuita de Android Academy en CoddyKit. Esta es la lección 3 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é es importante la caché

Descargar y decodificar una imagen es costoso: consume ancho de banda, batería y CPU. Si vuelve a solicitar la misma imagen cada vez que se desplaza una lista, la aplicación parece lenta y consume datos innecesariamente.

La caché almacena imágenes decodificadas y bytes descargados para que la siguiente solicitud sea casi instantánea. Coil incluye dos cachés de forma predeterminada: una caché en memoria (rápida, con mapas de bits decodificados) y una caché en disco (persistente, con bytes sin procesar).

En esta lección se explica cómo funcionan y cómo ajustarlas.

Dos capas: memoria y disco

Coil comprueba las cachés en este orden:

  • Caché en memoria: contiene en la RAM los mapas de bits decodificados usados recientemente. Un acierto aquí es instantáneo, ya que no se necesita decodificar.
  • Caché en disco: almacena en el dispositivo los bytes originales descargados. Un acierto aquí evita la red, pero aún requiere decodificación.
  • Red: la ruta más lenta, que solo se usa cuando no hay aciertos en ninguna de las dos cachés.

La memoria es rápida, pero limitada, y se borra cuando la aplicación finaliza; el disco es más grande y sobrevive a los reinicios.

Configuración de ImageLoader

Las cachés pertenecen a ImageLoader, el motor que está detrás de cada solicitud. Normalmente se crea un cargador personalizado y se reutiliza. Aquí se configura la caché en memoria con un porcentaje de la RAM disponible y la caché en disco con un límite fijo de bytes.

Un cargador singleton evita duplicar cachés y desperdiciar memoria.

import android.content.Context
import coil3.ImageLoader
import coil3.disk.DiskCache
import coil3.memory.MemoryCache
import okio.Path.Companion.toOkioPath

fun newImageLoader(context: Context): ImageLoader =
    ImageLoader.Builder(context)
        .memoryCache {
            MemoryCache.Builder()
                .maxSizePercent(context, 0.25) // 25% of app RAM
                .build()
        }
        .diskCache {
            DiskCache.Builder()
                .directory(context.cacheDir.resolve("image_cache").toOkioPath())
                .maxSizeBytes(50L * 1024 * 1024) // 50 MB
                .build()
        }
        .build()

Proporcionar un cargador singleton

Coil 3 permite establecer un único cargador para toda la aplicación implementando SingletonImageLoader.Factory en la clase Application. Después, todos los AsyncImage lo utilizan automáticamente, sin necesidad de pasar un cargador cada vez.

import android.app.Application
import coil3.ImageLoader
import coil3.PlatformContext
import coil3.SingletonImageLoader

class MyApp : Application(), SingletonImageLoader.Factory {
    override fun newImageLoader(context: PlatformContext): ImageLoader =
        ImageLoader.Builder(context)
            .crossfade(true)
            .build()
}

Controlar las políticas de caché

Cada solicitud puede activar o desactivar la caché mediante memoryCachePolicy y diskCachePolicy. Las políticas son ENABLED, READ_ONLY, WRITE_ONLY o DISABLED.

Por ejemplo, desactive la caché en memoria para imágenes enormes y puntuales que no quiera conservar en la RAM, o desactive el disco para contenido sensible.

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

fun noMemoryCacheRequest(context: Context, url: String) =
    ImageRequest.Builder(context)
        .data(url)
        .memoryCachePolicy(CachePolicy.DISABLED)
        .diskCachePolicy(CachePolicy.ENABLED)
        .build()

Cambiar el tamaño: no decodifique mapas de bits enormes

El mayor error de rendimiento consiste en decodificar una foto de 4000x3000 en una miniatura de 100dp. Esto desperdicia memoria y tiempo. De forma predeterminada, Coil ajusta el tamaño del mapa de bits a los límites medidos del composable, por lo que un AsyncImage pequeño decodifica un mapa de bits pequeño.

Puede forzar un tamaño de destino explícito con size() en la solicitud cuando conozca las dimensiones.

import android.content.Context
import coil3.request.ImageRequest
import coil3.size.Size

fun thumbnailRequest(context: Context, url: String) =
    ImageRequest.Builder(context)
        .data(url)
        .size(Size(200, 200)) // decode at most 200x200
        .build()

Claves de caché estables

Coil obtiene una clave de caché a partir de los datos de la solicitud. Si las URL contienen parámetros de consulta cambiantes (como un token firmado), las imágenes idénticas obtienen claves distintas y nunca encuentran un acierto en la caché.

Establezca explícitamente memoryCacheKey y diskCacheKey basándose en la parte estable (como el ID de la imagen) para que el almacenamiento en caché funcione.

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

fun stableKeyRequest(context: Context, id: String, signedUrl: String) =
    ImageRequest.Builder(context)
        .data(signedUrl)
        .memoryCacheKey("image_$id")
        .diskCacheKey("image_$id")
        .build()

Precargar imágenes

Para ofrecer una experiencia más fluida, puede calentar la caché antes de mostrar una imagen; por ejemplo, precargando la página siguiente de un feed. Use enqueue del cargador con una solicitud que no tenga destino.

Cuando el usuario llegue a la imagen, esta ya estará en la caché y aparecerá al instante.

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

fun preload(context: Context, loader: ImageLoader, urls: List<String>) {
    urls.forEach { url ->
        val request = ImageRequest.Builder(context)
            .data(url)
            .build()
        loader.enqueue(request)
    }
}

Borrar la caché

En ocasiones necesita liberar espacio o forzar una actualización, por ejemplo, después de que el usuario actualice su avatar. Puede borrar la caché en memoria, la caché en disco o eliminar una sola clave.

Borrarlo todo es una operación costosa; siempre que pueda, prefiera eliminar claves específicas.

import coil3.ImageLoader
import coil3.memory.MemoryCache

fun refreshAvatar(loader: ImageLoader, key: String) {
    // Remove one entry so the next load refetches
    loader.memoryCache?.remove(MemoryCache.Key(key))
    loader.diskCache?.remove(key)
}

fun clearAll(loader: ImageLoader) {
    loader.memoryCache?.clear()
    // Disk clearing is heavier; do it sparingly
}

Fundido frente a aciertos de caché

El fundido queda muy bien durante las cargas desde la red, pero puede resultar lento cuando una imagen procede directamente de la caché en memoria y podría mostrarse al instante. Coil lo gestiona de forma inteligente: de manera predeterminada, omite la animación de fundido para los aciertos de la caché en memoria y solo anima las imágenes cargadas realmente.

Así obtiene fundidos fluidos durante la primera carga y una visualización instantánea al desplazarse por imágenes almacenadas en caché, sin necesidad de trabajo adicional.

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

fun feedRequest(context: Context, url: String) =
    ImageRequest.Builder(context)
        .data(url)
        // Crossfade plays on real loads; memory-cache hits show instantly
        .crossfade(true)
        .build()

Lista de comprobación de rendimiento para listas

Al mostrar muchas imágenes en una LazyColumn o cuadrícula, siga estas reglas para conseguir un desplazamiento fluido:

  • Asigne a cada imagen un tamaño fijo para que Coil decodifique un mapa de bits pequeño.
  • Reutilice un único ImageLoader singleton para compartir las cachés.
  • Use ContentScale.Crop para evitar cambios de diseño.
  • Mantenga estables las claves de caché entre recargas.
  • Deje que Coil cancele automáticamente las solicitudes fuera de pantalla; no interfiera con ello.
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import coil3.compose.AsyncImage

@Composable
fun PhotoGrid(urls: List<String>) {
    LazyVerticalGrid(columns = GridCells.Fixed(3)) {
        items(urls) { url ->
            AsyncImage(
                model = url,
                contentDescription = null,
                contentScale = ContentScale.Crop,
                modifier = Modifier.aspectRatio(1f)
            )
        }
    }
}

Comprobación rápida

Coil comprueba sus cachés antes de acceder a la red. ¿Qué caché es la más rápida cuando hay un acierto, porque evita por completo la decodificación?

Resumen

Ha aprendido cómo consigue Coil que las imágenes se carguen rápidamente:

  • Dos cachés: memoria (decodificada, rápida y pequeña) y disco (bytes sin procesar, persistente y más grande).
  • Configure los tamaños en un ImageLoader personalizado y exponga uno mediante SingletonImageLoader.Factory.
  • Ajuste el comportamiento de cada solicitud con memoryCachePolicy y diskCachePolicy.
  • Decodifique siempre al tamaño de visualización; establezca size() explícitamente cuando sea necesario.
  • Use claves de caché estables, precargue las próximas imágenes y borre claves específicas para actualizar el contenido.

A continuación: ir más allá de las imágenes para reproducir audio y vídeo.

Preguntas frecuentes

¿La lección «Caché y rendimiento» es gratis?

Sí — el texto completo de «Caché y rendimiento» 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 «Caché y rendimiento»?

Conceptos básicos de la caché en memoria y en disco 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 3 de 4.

¿Cuánto tiempo toma la lección «Caché y rendimiento»?

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