Es casi imposible encontrar una aplicación Android moderna que no muestre imágenes, ya sean fotos de productos, avatares o elementos decorativos de la interfaz de usuario. Por muy habitual que sea, la carga de imágenes puede ser una tarea sorprendentemente compleja: se necesita una obtención asíncrona, almacenamiento en caché, visualización de marcadores de posición, gestión de errores y, a veces, animaciones o transformaciones. Como empresa de desarrollo de aplicaciones Android con más de 16 años de experiencia, lo sabemos de primera mano. Por suerte, varias bibliotecas bien establecidas -Picasso, Glide y Fresco- se ocupan de estos detalles con facilidad.
A partir de 2025, estos tres recursos siguen siendo los principales contendientes para la carga de imágenes en Android, cada uno con sus propias ventajas. A continuación, compararemos sus estrategias de almacenamiento en caché, sus API de transformación, sus capacidades de animación y sus características «deseables», para ayudarte a elegir la que mejor se adapte a tu proyecto.
Biblioteca
Picasso
- Orígenes: Creado por Square, conocido por OkHttp, Retrofit y LeakCanary
- Filosofía: Enfoque minimalista, menor huella (añade ~121 KB, ~849 métodos)
- Ventajas: API sencilla, configuración rápida, excelente para casos de uso básicos
- Contras: Funciones avanzadas limitadas; para transformaciones más complejas o controles de animación, es necesario recurrir a extensiones de terceros
Glide
- Origen: Desarrollado por BumpTech (ahora parte del ecosistema de código abierto de Google)
- Filosofía: Funcionalidad robusta y transformaciones flexibles
- Huella: Más grande (~440 KB, ~2678 métodos)
- Ventajas: Potente sistema de almacenamiento en caché, compatibilidad integrada con GIF, transformaciones avanzadas y animaciones cross-fade sencillas
- Contras: Mayor tamaño de la biblioteca y número de métodos
Fresco
- Origen: Creado por Facebook
- Filosofía: Alto rendimiento y gestión eficiente de la memoria, especialmente en versiones antiguas de Android.
- Detalle de implementación: Utiliza su propio
SimpleDraweeView
en lugar deImageView
- Ventajas: Gestiona las imágenes fuera de la pila tradicional de Java, reduciendo
OutOfMemoryError
. Bueno para UIs complejas o dispositivos antiguos - Contras: Arquitectura más especializada; las transformaciones pueden ser más complicadas
Almacenamiento en caché y gestión de memoria
Las imágenes pueden estar entre los activos más grandes de cualquier aplicación Android, ejerciendo presión tanto sobre el ancho de banda de la red como sobre la memoria del dispositivo. Un almacenamiento en caché eficaz garantiza que las imágenes más solicitadas se carguen al instante, lo que elimina las descargas innecesarias y reduce el uso de datos móviles. Una buena gestión de la memoria también evita la lentitud del rendimiento o los bloqueos causados por una memoria RAM insuficiente, especialmente en dispositivos antiguos o de gama baja.
Picasso
- Cachés por defecto:
- Memoria: Caché LRU (~15% de la RAM disponible de la aplicación).
- Disco: 5-50 MB (se ajusta automáticamente en función del almacenamiento).
- Ajustes:
memoryPolicy()
ynetworkPolicy()
permiten controlar el comportamiento de la caché.
Por ejemplo, una petición de este tipo obligará a Picasso a descargar constantemente imágenes de la red:
Picasso.get()
.load(imageUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(testImageView)
Deslizamiento
- 4 niveles de caché:
- Recursos activos (mostrados ahora)
- Caché de Memoria (decodificado en RAM)
- Caché de disco de recursos (convertidos/decodificados en disco)
- Caché de disco de datos (datos de imagen sin procesar en disco)
- Estrategia de caché de disco:
ALL, DATA, RESOURCE, NONE
. Puede omitir la caché de memoria conskipMemoryCache(true)
. - Claves personalizadas: Utilice
signature()
para diferenciar varias versiones de la misma imagen (por ejemplo, para diferentes transformaciones).
Fresco
- 3 niveles de caché:
- Mapa de bits (descodificado, listo para su visualización)
- Memoria codificada (imagen original comprimida en memoria)
- Disco (imagen original comprimida en almacenamiento local)
- Gestión: Clase
ImagePipeline
para comprobar, desalojar o borrar cachés.
Ejemplo:
val imagePipeline = Fresco.getImagePipeline()
imagePipeline.evictFromMemoryCache(uri)
imagePipeline.evictFromDiskCache(uri)
imagePipeline.clearMemoryCaches()
imagePipeline.clearDiskCaches()
- Cachés de imágenes pequeñas: Opcionalmente mantener una caché de miniaturas separada, aumentando el rendimiento.
Transformaciones y procesamiento avanzado de imágenes
Una de las principales ventajas que ofrecen los cargadores de imágenes es la posibilidad de procesar las imágenes antes de que aparezcan en la pantalla. Esto permite a los desarrolladores unificar la marca, ahorrar ancho de banda mediante la optimización sobre la marcha o aplicar efectos creativos que aumentan la participación del usuario. Sin transformaciones integradas, los equipos tendrían que escribir complejas lógicas personalizadas, algo que estas bibliotecas gestionan de forma inmediata, ahorrando tiempo y esfuerzo.
Picasso
- Integradas:
resize()
,centerCrop()
,centerInside()
,rotate()
. - Personalizadas: Hereda de
Transformation
, define tu lógica entransform()
y una clavekey()
. - Extensiones de terceros: por ejemplo, la biblioteca Wasabeef para transformaciones de formas, desenfoques y filtros.
Ejemplo: Transformación de círculo
class CircleTransformation : Transformation {
override fun transform(source: Bitmap): Bitmap {
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val output = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
canvas.drawCircle(source.width / 2f, source.height / 2f, source.width / 2f, paint)
if (source != output) source.recycle()
return output
}
override fun key() = "circle"
}
Deslizamiento
- Integradas:
resize()
,centerCrop()
,circleCrop()
,roundedCorners()
, etc. - Personalizadas:
BitmapTransformation
,DrawableTransformation
, etc. Debe anularequals()
,hashCode()
,transform()
yupdateDiskCacheKey()
. - De terceros: Del mismo modo, las bibliotecas Wasabeef o Werbhelius para más filtros.
Ejemplo: Transformación de escala de grises
class GreyscaleTransformation : BitmapTransformation() {
override fun transform(pool: BitmapPool, source: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
val bitmap = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
val paint = Paint()
val greyMatrix = ColorMatrix().apply { setSaturation(0f) }
paint.colorFilter = ColorMatrixColorFilter(greyMatrix)
Canvas(bitmap).drawBitmap(source, 0f, 0f, paint)
return bitmap
}
// equals(), hashCode(), updateDiskCacheKey() ...
}
Fresco
- XML frente a código: Muchas transformaciones pueden especificarse directamente en el diseño XML mediante atributos.
- Postprocesador: Extender
BasePostprocessor
para definir transformaciones personalizadas (similar a un enfoque de «dibujar en mapa de bits»).
Ejemplo: Redondee las esquinas fácilmente con:
val roundingParams = RoundingParams.fromCornersRadius(7f)
val hierarchy = GenericDraweeHierarchyBuilder(resources)
.setRoundingParams(roundingParams)
.build()
frescoImageView.hierarchy = hierarchy
- Limitaciones: Algunas transformaciones sólo se aplican a formatos específicos (por ejemplo, JPEG), y ciertos escalados están restringidos.
Soporte de animaciones
Las transiciones suaves y la respuesta del usuario son las piedras angulares de una gran experiencia de usuario móvil. Los sutiles efectos de fundido evitan que la carga de imágenes resulte brusca, mientras que las barras de progreso aseguran a los usuarios que el contenido está en camino. Las animaciones posteriores a la carga, como la rotación o el rebote, pueden añadir un toque extra de personalidad, resaltar elementos visuales clave y reforzar la identidad de la marca.
Efectos de fundido
- Picasso: Desvanecimiento básico incorporado (se activa siempre que la imagen no procede de la memoria). No se puede personalizar la duración; sólo
fadeEnabled
/fadeDisabled
. - Deslizamiento:
- Utilice
transition(DrawableTransitionOptions.withCrossFade(duration))
. - Admite el desvanecimiento cruzado (imagen antigua fuera, imagen nueva dentro) o una superposición de desvanecimiento más sencilla. Si es necesario, también puede definir animaciones XML personalizadas.
- Utilice
- Fresco:
Establezca la duración del desvanecimiento mediante el diseño XML o el código:
val builder = GenericDraweeHierarchyBuilder(resources)
val hierarchy = builder.setFadeDuration(3000).build()
frescoImageView.hierarchy = hierarchy
- Siempre utiliza un enfoque de fundido cruzado; puede consumir muchos recursos con listas grandes.
Barras de progreso
- Picasso:
- La ruta más fácil: utilizar un marcador de
placeholder(R.drawable.progress_animation)
. - O implementar un
Target
personalizado para mostrar/ocultar unaProgressBar
mientras se cargan las imágenes.
- La ruta más fácil: utilizar un marcador de
- Glide:
- Un enfoque similar utiliza marcadores de posición o
RequestListener
personalizados para realizar un seguimiento del estado de carga. - Algunos desarrolladores anulan
GlideModule
para interceptar y medir el progreso con mayor precisión.
- Un enfoque similar utiliza marcadores de posición o
- Fresco:
- En XML, define
fresco:progressBarImage="@drawable/spinner"
.
- En XML, define
En el código:
val progressDrawable = ProgressBarDrawable().apply {
color = Color.YELLOW
backgroundColor = Color.BLUE
radius = 2
}
frescoImageView.hierarchy.setProgressBarImage(progressDrawable)
- Fresco muestra fácilmente barras de progreso tanto indefinidas como porcentuales con un esfuerzo mínimo.
Animaciones posteriores a la carga (por ejemplo, rotación de imágenes)
- Picasso:
- Usa un
Callback
ininto(...)
. EnonSuccess()
, ejecute su código de animación (por ejemplo,startAnimation(rotateAnimation))
.
- Usa un
- Glide:
- Implementa un
RequestListener
y anulaonResourceReady()
. Ejecute allí su animación.
- Implementa un
- Fresco:
- Crea un
BaseControllerListener
. EnonFinalImageSet()
, dispara la animación (frescoImageView.startAnimation(...)
).
- Crea un
Características únicas
Más allá del almacenamiento en caché y la transformación estándar, cada biblioteca destaca en áreas específicas que pueden inclinar la balanza de tu elección de desarrollo. He aquí un rápido vistazo a lo que diferencia a cada biblioteca:
- Picasso: Minimalista, ocupa poco espacio. Ideal para la carga directa de imágenes. Carece de animaciones robustas incorporadas, pero es fácil de aprender para los recién llegados.
- Glide: Ricas transformaciones, soporte GIF incorporado, personalización flexible (por ejemplo, pilas de red personalizadas). Mantiene múltiples versiones de imágenes en la caché para diferentes tamaños o transformaciones.
- Fresco: Gestión innovadora de la memoria (almacenamiento de imágenes fuera de la pila de Java). Notable mejora del rendimiento en dispositivos Android antiguos.
SimpleDraweeView
propio puede simplificar los marcadores de posición, las barras de progreso y las transiciones de fundido.
Tabla comparativa para 2025
A continuación se muestra una tabla comparativa concisa que destaca las diferencias clave entre Picasso, Glide y Fresco en 2025. Utilícela como referencia rápida a la hora de decidir qué biblioteca se adapta mejor a los requisitos de carga de imágenes de su proyecto Android.
Tamaño de la biblioteca
~121 KB + ~849 métodos
~440 KB + ~2678 métodos
~500 KB (varía), uso de memoria de la pila de Java
Facilidad de uso
Alta (muy apta para principiantes)
Alta (API rica, curva de aprendizaje moderada)
Media (SimpleDraweeView
personalizada + diferentes patrones de uso)
Animación (fundido, fundido cruzado)
Opción integrada de fundido o desactivado, no personalizable
Transiciones totalmente personalizables (duración, fundido cruzado, XML personalizado)
Configuración de fundido simple; siempre fundido cruzado; puede consumir muchos recursos con listas grandes
Barras de progreso
Requiere marcadores de posición personalizados o Target
Marcadores de posición personalizados o anulación de GlideModule
Configuración rápida mediante XML o código, admite barras indefinidas y porcentuales
Funciones de transformación
Incorporaciones básicas; las transformaciones personalizadas requieren una interfaz de Transformation
Potentes funciones integradas, transformaciones personalizadas sencillas (BitmapTransformation, etc.)
Transformaciones avanzadas, muchas en XML; los postprocesadores personalizados pueden ser más complejos
Almacenamiento en caché
LRU (memoria + disco); control mediante memoryPolicy()
& networkPolicy()
Caché de 4 niveles; salta fácilmente de memoria o disco, teclas personalizadas avanzadas
Caché de 3 niveles (mapa de bits, memoria codificada, disco); ImagePipeline
para un control preciso
Mejora del rendimiento
Bueno para imágenes pequeñas, transformaciones limitadas
Sobresale con GIF, transformaciones pesadas, múltiples variantes de imagen
Muy eficiente en memoria en dispositivos antiguos, menos sobrecarga GC
Funciones destacadas
Ocupa poco espacio, fácil de integrar, rápido de aprender
Carga de GIF, compatibilidad con fotogramas de vídeo, pila de red personalizada, amplia API de transformación
Imágenes en ashmem heap, compatibilidad con JPEG progresivo, marcadores de posición y barras de progreso integrados
Conclusión
Picasso es ideal para tareas de imagen sencillas en las que lo más importante es una configuración mínima y un tamaño de APK reducido.
Glide sigue siendo la mejor opción para transformaciones complejas, compatibilidad con GIF y almacenamiento en caché de múltiples variantes, aunque es más pesada en cuanto al tamaño del APK. Vea cómo utilizamos las eficientes capacidades de carga de imágenes y almacenamiento en caché de Glide para optimizar Android Bug Hunter, una solución móvil que simplifica las pruebas manuales de interfaz de usuario y las pruebas de baja memoria de aplicaciones Android.
Fresco sobresale en escenarios sensibles a la memoria, especialmente en dispositivos antiguos o feeds con muchas imágenes, gracias a su enfoque distintivo de almacenamiento de imágenes fuera del montón estándar de Java.
Estas tres bibliotecas seguirán dominando la carga de imágenes en Android en 2025, ya que cada una de ellas ofrece sólidas capacidades de almacenamiento en caché, transformación y animación. La mejor opción depende de las necesidades específicas de su aplicación, ya sea un uso más sencillo, transiciones avanzadas u optimización de la memoria. En Redwerk, hemos desarrollado soluciones Android para los sectores de telecomunicaciones, TI y comercio electrónico. Estamos dispuestos a ayudarle a perfeccionar su estrategia de carga de imágenes. No dude en ponerse en contacto con nosotros si desea asesoramiento experto para su próximo proyecto.