Picasso: librería de imágenes para Android y Kotlin
Mostrar una foto de internet en una app Android parece fácil, pero hay mucho trabajo detrás: descargarla en otro hilo para no congelar la pantalla, reducirla para no agotar la memoria, guardarla para no descargarla dos veces y cancelar la descarga si el usuario sale de la pantalla.
Picasso es como un recadero que va a por las fotos, las recorta a la medida del marco y guarda una copia en un álbum (la caché). La próxima vez que le pidas la misma foto, la saca del álbum en lugar de volver a la tienda.
Se puede hacer todo esto sin librería, pero Picasso lo resuelve por ti: hilos, memoria, caché, descarga, redimensionado, imágenes circulares y animaciones.
Añadir Picasso a tu proyecto con Gradle
En 2018 copiaba la dependencia de la web de Picasso, que entonces anunciaba la versión 2.71828.
Y la pegaba al final del bloque dependencies del build.gradle del módulo app:
dependencies {
// ... las dependencias que ya traía el proyecto
implementation 'com.squareup.picasso:picasso:2.71828'
}
Hoy, la última versión es la 2.8. En un proyecto actual, el fichero suele llamarse build.gradle.kts (Gradle con Kotlin) y la línea queda así:
dependencies {
implementation("com.squareup.picasso:picasso:2.8")
}
Pulsa Sync Now y Gradle la descarga. Si quieres entender qué hace Gradle por debajo, lo explico en Gradle en Android.
Permiso de internet
Para descargar imágenes, la app necesita permiso para usar internet. Se declara en el AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Cargar una imagen con Picasso en Kotlin
La idea es siempre la misma: Picasso.get(), qué imagen cargar (load), qué hacerle y dónde ponerla (into).
// En onCreate(): descarga la imagen y la guarda en caché, sin mostrarla.
Picasso.get().load(URL_FLAMENCO).fetch()
// Al pulsar el botón: la pone en los ImageView.
fun cargarImagenes(imageViewArriba: ImageView, imageViewAbajo: ImageView) {
Picasso.get()
.load(URL_FLAMENCO)
.resize(400, 400) // la reduce a 400 × 400 píxeles
.centerInside() // cabe entera dentro de ese tamaño
.into(imageViewArriba)
Picasso.get()
.load(URL_BOSQUE)
.fit() // la ajusta al tamaño del ImageView
.centerCrop() // rellena el hueco y recorta lo que sobra
.into(imageViewAbajo)
}
fetch() es la precarga: el recadero trae la foto y la deja en el álbum antes de que la pidas. Si ejecutas la app, la imagen precargada aparece mucho más rápido la primera vez que la que no lo estaba. Si no recuerdas cuándo se llama a onCreate(), lo tienes en el ciclo de vida de las Activities.
Así estaba en la versión original del artículo. Usa las vistas sintéticas de kotlin-android-extensions, un plugin ya retirado que hoy no compila; ahora se usa View Binding:
class PicassoActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_picasso_activity)
buttonLoader.setOnClickListener{loadImages()}
Picasso.get().load("https://html.com/wp-content/uploads/flamingo.jpg").fetch()
}
private fun loadImages(){
Picasso
.get()
.load("https://html.com/wp-content/uploads/flamingo.jpg")
.resize(400, 400)
.centerInside()
.into(imageViewTop)
Picasso
.get()
.load("https://www.w3schools.com/css/img_forest.jpg")
.fit()
.into(imageViewButtom)
}
}
Cargar desde un fichero o un recurso
load() no solo acepta URLs. También vale para un File, un Uri o un recurso de la app:
Picasso.get().load(fichero).into(imageView) // un File del dispositivo
Picasso.get().load(R.drawable.foto).into(imageView) // un recurso de la app
Tipos de alineado: resize, fit, centerInside y centerCrop
| Método | Qué hace | Ten en cuenta |
|---|---|---|
fit() |
Ajusta la imagen al tamaño del ImageView |
No se puede combinar con resize() ni usar con fetch() |
resize(ancho, alto) |
La redimensiona a los píxeles que indiques | Ahorra memoria con imágenes grandes |
centerInside() |
La encaja entera y centrada; puede sobrar hueco | Necesita resize() o fit() |
centerCrop() |
Rellena todo el hueco, centrada, y recorta lo que sobra | Necesita resize() o fit() |
Un símil: centerInside es meter una foto en un marco sin cortarla, aunque queden bordes; centerCrop es recortarla con tijeras para que llene el marco.
Renderizar una imagen de forma circular
Picasso no trae una imagen circular de serie. Se consigue con una transformación: una clase que recibe la imagen y devuelve otra modificada. En 2018 usaba una clase en Java de un gist de terceros; esta es una versión en Kotlin:
class CircleTransform : Transformation {
override fun transform(source: Bitmap): Bitmap {
// 1. Recorta un cuadrado centrado.
val lado = minOf(source.width, source.height)
val x = (source.width - lado) / 2
val y = (source.height - lado) / 2
val cuadrada = Bitmap.createBitmap(source, x, y, lado, lado)
if (cuadrada != source) source.recycle()
// 2. Pinta ese cuadrado dentro de un círculo.
val redonda = Bitmap.createBitmap(lado, lado, Bitmap.Config.ARGB_8888)
val pincel = Paint(Paint.ANTI_ALIAS_FLAG).apply {
shader = BitmapShader(cuadrada, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
}
val radio = lado / 2f
Canvas(redonda).drawCircle(radio, radio, radio, pincel)
cuadrada.recycle()
return redonda
}
override fun key() = "circle" // identifica la transformación en la caché
}
Y la aplicas con transform():
Picasso.get()
.load(URL_BOSQUE)
.fit()
.centerCrop()
.transform(CircleTransform())
.into(imageView)
Animación de fundido (fade)
Picasso ya aplica un fundido corto cuando la imagen llega de la red o del disco. Si quieres uno más largo, por ejemplo de 3 segundos, desactiva el suyo con noFade() y anima tú el ImageView cuando la imagen esté lista:
imageView.alpha = 0f
Picasso.get()
.load(URL_BOSQUE)
.noFade()
.into(imageView, object : Callback {
override fun onSuccess() {
imageView.animate().setDuration(3000).alpha(1f).start()
}
override fun onError(e: Exception) {
imageView.alpha = 1f // que no se quede invisible si falla
}
})
En la versión original usaba fetch() con un Callback y, al terminar, volvía a pedir la imagen con into():
Picasso.get()
.load("https://www.w3schools.com/css/img_forest.jpg")
.fetch(object:Callback{
override fun onSuccess() {
imageViewButtom.alpha = 0f
Picasso.get()
.load("https://www.w3schools.com/css/img_forest.jpg")
.fit()
.into(imageViewButtom)
imageViewButtom.animate().setDuration(3000).alpha(1f).start()
}
override fun onError(e: Exception?) {
}
})
La versión nueva hace una sola petición, quita el fundido de Picasso para que no se sumen dos y deja la imagen visible si la descarga falla.
La caché de Picasso
Picasso guarda las imágenes en dos sitios: en memoria, para lo que acabas de ver, y en disco, en la carpeta picasso-cache dentro de la caché de la app.
Ver y borrar la caché desde Device Explorer
Abre View > Tool Windows > Device Explorer en Android Studio (en versiones antiguas se llamaba Device File Explorer), o pulsa su botón en la barra lateral.
En el ejemplo, la carpeta de la aplicación está dentro de data/data/com.rubentejera.seccion4cursokotlin. Dentro, en cache/picasso-cache, están las imágenes precargadas:

Para borrar la caché, borra la carpeta picasso-cache (clic derecho > Delete).
Saltarse la caché desde el código
Si una imagen cambia en el servidor pero conserva la URL, puedes pedir a Picasso que no use la caché para esa petición:
Picasso.get()
.load(URL_BOSQUE)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE) // ni lee ni guarda en memoria
.networkPolicy(NetworkPolicy.NO_CACHE) // no lee la caché de disco
.into(imageView)
O borrar de la memoria una imagen concreta con Picasso.get().invalidate(URL_BOSQUE).
La alternativa hoy: Coil o Glide
Si empiezas un proyecto, no elijas Picasso. La documentación oficial de Android propone estas dos librerías para cargar imágenes en Compose:
Coil
- La que recomienda Square para sustituir a Picasso
- Pensada para Kotlin, corrutinas y Compose
- Versión 3.6.3; Android 6.0 (API 23) o superior
Glide
- Mantenida, con versiones nuevas cada cierto tiempo
- API parecida a la de Picasso
- Versión 5.0.9; Android 6.0 (API 23) o superior
Coil con vistas (ImageView)
dependencies {
implementation("io.coil-kt.coil3:coil:3.6.3")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.6.3")
}
El mismo ejemplo de la imagen redonda con fundido de 3 segundos:
imageView.load(URL_BOSQUE) {
crossfade(3000) // fundido de 3 segundos
transformations(CircleCropTransformation()) // recorte circular de serie
}
Fíjate en que Coil trae el recorte circular incluido y detecta solo cómo ajustar la imagen al ImageView.
Coil con Jetpack Compose
dependencies {
implementation("io.coil-kt.coil3:coil-compose:3.6.3")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.6.3")
}
AsyncImage(
model = "https://example.com/image.jpg",
contentDescription = "Puente en un bosque",
)
Glide
dependencies {
implementation("com.github.bumptech.glide:glide:5.0.9")
}
Glide.with(imageView)
.load(URL_BOSQUE)
.circleCrop()
.transition(DrawableTransitionOptions.withCrossFade(3000))
.into(imageView)
Equivalencias para migrar
| Picasso | Coil | Glide |
|---|---|---|
Picasso.get().load(url).into(iv) |
iv.load(url) |
Glide.with(iv).load(url).into(iv) |
.transform(CircleTransform()) |
transformations(CircleCropTransformation()) |
.circleCrop() |
Fundido con Callback |
crossfade(3000) |
.transition(DrawableTransitionOptions.withCrossFade(3000)) |
.fit() |
Automático | Automático según el scaleType |
Coil tiene una guía oficial para migrar desde Picasso y Glide con más casos.
Una librería obsoleta no se rompe de golpe: se queda atrás poco a poco.
Siguiente paso
- Busca
com.squareup.picassoen tus ficheros de Gradle para saber si tu app lo usa. - Si lo usa, sube a la 2.8 mientras planificas el cambio.
- Migra una pantalla a Coil, comprueba que se ve igual y sigue con las demás.
Si estás empezando con Android y Kotlin, el punto de partida es el Hola Mundo con Android Studio y Kotlin.
Fuentes
Comprobado el 7 de noviembre de 2026:
- Repositorio oficial de Picasso (README con el aviso de obsolescencia y la versión 2.8) y su registro de versiones en Maven Central: la 2.8 se publicó el 10 de agosto de 2020 y la 2.71828, el 7 de marzo de 2018.
- Documentación de Coil (versión 3.6.3) y su guía de migración desde Picasso y Glide.
- Repositorio oficial de Glide (versión 5.0.9).
- El API mínimo de Coil 3.6.3 y Glide 5.0.9 (23) sale del
AndroidManifest.xmlde sus paquetes publicados. - Android Developers: Device Explorer y Cargar imágenes en Compose.
- Gradle 9.9: cómo compara las versiones.
Los ejemplos en Kotlin de Picasso 2.8, Coil 3.6.3 (vistas) y Glide 5.0.9 se han compilado con kotlinc 2.4.21 contra las librerías publicadas en Maven Central, pero no se han ejecutado en un dispositivo. El ejemplo de Compose es el de la documentación oficial de Coil. La captura es de la versión original del artículo (2018), hecha con Picasso 2.71828 en un Xiaomi Mi Max 2 con Android 7.1.1.