Il est presque impossible de trouver une application Android commerciale qui n’utilise pas d’images dans son interface. Le téléchargement d’une image dans la Vue correspondante, malgré la simplicité apparente de l’opération, peut causer de gros problèmes au développeur. Par exemple, que faire si l’image est stockée sur le serveur ? Pour l’afficher à l’écran, vous devriez d’abord la charger dans le stockage local, puis la convertir au format désiré, et l’ajouter comme attribut dans la Vue. La liste des tâches s’allongera considérablement si nous voulons réutiliser les images déjà chargées ou afficher un placeholder pendant que l’image désirée est en cours de téléchargement. C’est pourquoi la grande majorité des projets Android utilisent des bibliothèques spéciales – des téléchargeurs d’images qui vous permettent de briser ce cycle sans fin. Les plus courantes en 2020 sont Picasso, Glide et Fresco.
A été créé par Square, une entreprise connue de la communauté Android pour des bibliothèques populaires telles que Retrofit, OkHttp et Leak Canary. Les créateurs de cette bibliothèque ont mis l’accent principal sur la simplicité et la clarté du travail. L’approche minimaliste permet de ne pas alourdir la taille du fichier apk – Picasso ne pèse que 121 Ko. La bibliothèque permet également de limiter le nombre de méthodes dans l’application, n’en ajoutant que 849. Cela retarde le moment où l’application devra passer à un fichier multidex.
Est un produit de Bump Tech. L’une des caractéristiques marquantes de cette bibliothèque est sa fonctionnalité puissante qui vous permet de réaliser des transformations d’images complexes. Cependant, cela a un coût – une application plus volumineuse : Glide ajoute 440 Ko et 2678 méthodes. Par conséquent, la niche de Glide dans le développement d’applications Android est un programme avec une logique d’affichage d’images complexe. Cependant, il est également tout à fait possible d’implémenter des solutions plus simples avec son aide.
A été créé par des ingénieurs de Facebook. Lors du chargement d’images, cette bibliothèque se concentre sur une gestion efficace de la mémoire et sur la productivité. Son avantage par rapport aux autres téléchargeurs d’images était particulièrement significatif sur les appareils sous Android 4. Désormais, l’écart s’est réduit, mais Fresco continue de dominer dans ce domaine. La deuxième caractéristique significative de Fresco est l’utilisation de son propre SimpleDraweeView à la place du traditionnel ImageView.
Une comparaison des fonctions simples de ces bibliothèques (chargement de ressources, gestion des erreurs, placeholders) n’apportera pas beaucoup de valeur au développeur Android, car ces fonctions sont intuitives et faciles à maîtriser en une heure seulement. Il serait plus intéressant de comparer les fonctionnalités avancées de Picasso, Glide et Fresco : la mise en cache et la transformation des images, ainsi que les outils uniques de chaque bibliothèque.
Mise en cache des images
Picasso prend en charge 2 types de cache par défaut : un cache LRU d’une taille de 15 % de la RAM disponible pour l’application, et un cache disque d’une taille allant de 5 à 50 Mo (dépend de la taille disponible de la mémoire morte). Les fonctions memoryPolicy() et networkPolicy() sont utilisées pour les contrôler. La première permet de refuser d’accéder au cache en ligne lors du chargement d’une image (attribut MemoryPolicy.NO_CACHE) ou de ne pas enregistrer l’image téléchargée dans le cache (attribut MemoryPolicy.NO_STORE). Avec la seconde, le cache disque est régulé. Ses attributs NetworkPolicy.NO_CACHE et NetworkPolicy.NO_STORE fonctionnent de la même manière qu’en MemoryPolicy. Un autre attribut – NetworkPolicy.OFFLINE – demande à Picasso de ne télécharger les données qu’à partir du cache, sans accéder au réseau.
Par exemple, une telle requête forcera Picasso à télécharger constamment des images depuis le réseau.
Picasso.get()
.load(imageUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.into(test_imageview)
Le schéma de mise en cache dans Glide est plus complexe. Il comporte 4 niveaux :
- ressources actives (affichées actuellement dans n’importe quelle Vue) ;
- cache mémoire (données en RAM) ;
- ressource (image convertie et décodée) ;
- Données (image brute enregistrée sur disque).
Par défaut, avant d’accéder à une ressource externe, Glide recherche une image appropriée à ces niveaux dans l’ordre. Avec cette approche, la même image peut avoir plusieurs versions. Par exemple, nous utilisons la même image à la fois dans la liste et dans la vue détaillée. Mais dans le premier cas, nous en extrayons une partie en utilisant le recadrage central, dans le second – nous l’affichons entièrement. Le cache contiendra 2 versions de cette image. Pour les distinguer, Glide utilise des clés qui incluent des informations sur la largeur et la hauteur de l’image, les transformations, les options ajoutées, le type de données, etc. Pour gérer le cache, utilisez la fonction diskCacheStrategy(), qui accepte les arguments énumérés de DiskCacheStrategy. ALL (utilise tous les niveaux de cache et une ressource externe), DATA (écrit des données brutes en mémoire morte), RESOURCE (écrit des données décodées en mémoire morte), NONE (ne met pas en cache les données dans la mémoire persistante).
L’exemple précédent de Picasso ressemblera à ceci :
Glide.with(this)
.load(imageUrl)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(test_imageview)
Comme Picasso, Glide vous permet de vider le cache complètement ou pour une image spécifique. Mais il permet également de le contrôler plus précisément en utilisant la fonction signature() et des clés personnalisées.
Le cache Fresco est également hiérarchique et comporte 3 niveaux :
- Bitmap (images décodées, prêtes à être affichées ou post-traitées) ;
- Cache mémoire encodé (stocke les images compressées dans leur état d’origine en mémoire) ;
- Disque (stocke les images compressées dans leur état d’origine dans le stockage local).
La bibliothèque utilise la classe ImagePipeline pour gérer le cache. Elle offre la possibilité de vérifier la présence d’images dans le cache, d’obtenir des images mises en cache ou de les supprimer.
val imagePipeline = Fresco.getImagePipeline()
// Vérifier si l'image est dans le cache
val inMemoryCache = imagePipeline.isInBitmapMemoryCache(uri)
// Obtenir l'image mise en cache
imagePipeline.evictFromMemoryCache(uri)
imagePipeline.evictFromDiskCache(uri)
// Vider le cache
imagePipeline.clearMemoryCaches()
imagePipeline.clearDiskCaches()
Une caractéristique intéressante de Fresco est la possibilité de créer un cache séparé pour stocker les petites images. Cela peut être utile pour améliorer les performances de l’application.
Transformation des images
L’un des principaux avantages de l’utilisation des téléchargeurs est la possibilité de traiter les images avant de les afficher à l’utilisateur. Picasso offre un ensemble de transformations simples intégrées : redimensionner, recadrer au centre, centrer à l’intérieur, faire pivoter. Pour des modifications plus complexes, vous pouvez utiliser des solutions prêtes à l’emploi de bibliothèques gratuites. Par exemple, une solution de Daichi Furiya (Wasabeef). Avec elle, vous pouvez facilement définir la forme complexe de l’image, le flou, ou appliquer des masques et des filtres. Il existe également une option pour créer votre propre transformation. Pour ce faire, vous devez hériter de la classe Transformation et définir la logique de modification de l’image. Il sera également nécessaire de définir une chaîne de clé unique pour cette transformation, ce qui nous permettra de distinguer les images traitées dans le cache.
Exemple de transformation circulaire
class CircleTransformation : Transformation {
override fun transform(source: Bitmap): Bitmap {
val paint = Paint()
paint.setAntiAlias(true)
paint.setShader(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 / 2, source.height / 2, source.width / 2, paint)
if (source != output)
source.recycle()
return output
}
override fun key(): String {
return "circle"
}
}
Le travail avec les transformations dans Glide est très similaire à celui de Picasso. Vous pouvez utiliser les options intégrées pour modifier les images (les mêmes que Picasso, plus circleCrop, roundedCorners, granularRoundedCorners). Pour des cas plus complexes, il existe des bibliothèques gratuites : de Daichi Furiya déjà mentionné (Wasabeef) ou de Werbhelius. Si nécessaire, vous pouvez toujours définir votre propre transformation. Son implémentation est légèrement différente de celle de Picasso. Tout d’abord, l’interface Transformation est le plus souvent implémentée non pas directement, mais à l’aide de classes utilitaires, chacune responsable de la transformation d’un certain type de ressource : DrawableTransformation, BitmapTransformation, GifDrawableTransformation, MultiTransformation, etc. Pour créer votre transformation, vous devez redéfinir 4 méthodes : equals() et hashcode() – pour distinguer les objets de transformation, transform() – décrit réellement la modification de l’image, updateDiskCacheKey() – permet d’identifier les images modifiées dans le cache.
Exemple de transformation personnalisée dans Glide
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()
greyMatrix.setSaturation(0.0f)
paint.colorFilter = ColorMatrixColorFilter(greyMatrix)
val canvas = Canvas(bitmap)
canvas.drawBitmap(source, 0f, 0f, paint)
return bitmap
}
override fun equals(other: Any?): Boolean {
return other is GreyscaleTransformation
}
override fun hashCode(): Int {
return Util.hashCode(ID.hashCode())
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update(ID_BYTES)
}
companion object {
private val ID = "GreyscaleTransformation"
private val ID_BYTES = ID.toByteArray()
}
}
Parmi les 3 téléchargeurs en question, Fresco possède les outils de transformation d’images les plus sophistiqués. La plupart d’entre eux peuvent être appliqués dans la mise en page xml, en indiquant les attributs correspondants. Du point de vue du codage, leur application est plus difficile. Par exemple, voici à quoi ressemble l’arrondi des coins lors de l’utilisation de Fresco.
val roundingParams = RoundingParams.fromCornersRadius(7f)
fresco_imageview.setHierarchy(
GenericDraweeHierarchyBuilder(resources)
.setRoundingParams(roundingParams)
.build()
)
De plus, certains outils standard ont des limitations. Par exemple, le redimensionnement ne peut être appliqué qu’au format JPEG, il ne peut pas agrandir une image et ne peut la réduire qu’à ⅛ de sa taille d’origine.
Comme d’autres chargeurs, Fresco peut être utilisé avec des bibliothèques de transformations prêtes à l’emploi (du même Wasabeef).
La création de votre transformation nécessite une implémentation personnalisée de la classe Postprocessor. Réécrivons l’exemple de niveaux de gris avec Glide pour Fresco.
class GrayScaleProcessor : BasePostprocessor() {
override fun process(bitmap: Bitmap) {
val w = bitmap.width
val h = bitmap.height
val pixels = IntArray(w * h)
bitmap.getPixels(pixels, 0, w, 0, 0, w, h)
for (x in 0 until w) {
for (y in 0 until h) {
val offset = y * w + x
pixels[offset] = getGreyColor(pixels[offset])
}
}
bitmap.setPixels(pixels, 0, w, 0, 0, w, h)
}
override fun getName(): String {
return "GrayScaleProcessor"
}
override fun getPostprocessorCacheKey(): CacheKey? {
return SimpleCacheKey("grayScale")
}
companion object {
internal fun getGreyColor(color: Int): Int {
val alpha = color and -0x1000000
val r = color shr 16 and 0xFF
val g = color shr 8 and 0xFF
val b = color and 0xFF
val luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b).toInt()
return alpha or (luminance shl 16) or (luminance shl 8) or luminance
}
}
}
Fonctionnalités uniques
Étant donné que Picasso a été basé sur le principe « rien de plus », il a ajouté la plupart des nouvelles fonctionnalités plus tard que ses concurrents, principalement Glide.
Glide a longtemps été un pionnier dans l’ajout de fonctionnalités aux téléchargeurs d’images sur Android. Actuellement, vous pouvez mettre en évidence ses fonctionnalités les plus utiles :
- chargement d’une image à partir d’une vidéo ;
- utilisation de tout type de modèle au lieu de Uri/String pour les chargeurs personnalisés ;
- téléchargement de GIF (également disponible dans Fresco) ;
- API flexible avec la possibilité de connecter n’importe quelle pile réseau (par exemple, Volley ou OkHttp).
Fresco a été créé comme une approche alternative pour le chargement d’images sur Android, en mettant l’accent sur l’efficacité. Par conséquent, ses principales caractéristiques sont cachées sous le capot :
- stockage des images non pas dans le tas Java, mais dans le tas ashmem, ce qui économise de la mémoire pour les applications, réduit les risques d’OutOfMemoryError et augmente les performances grâce à des appels moins fréquents du ramasse-miettes ;
- recadrage d’images autour de n’importe quel point, pas seulement au centre ;
redimensionnement de JPEG à l’aide de ressources natives, ce qui réduit également les risques d’OutOfMemoryError ; - support des images JPEG progressives.
Conclusion
| Critère | ![]() |
![]() |
![]() |
|---|---|---|---|
| Taille | 121 Ko | 440 Ko | 500 Ko |
| Facilité d’utilisation | élevée | élevée | moyenne |
| Vitesse de téléchargement web | élevée | légèrement inférieure en raison du long traitement de mise en cache | élevée |
| Vitesse de téléchargement depuis le cache | moyenne | élevée | élevée |
| Fonctionnalités de transformation intégrées | ensemble d’opérations de base | ensemble de base plus arrondi | capacités de transformation étendues, mais avec des limitations |
| Outils supplémentaires | Absent. | Chargement d’une image à partir d’une vidéo et GIF, utilisation de tout type de modèle, API flexible avec possibilité de connecter n’importe quelle pile réseau. | Stockage des images non pas dans le tas Java, mais dans le tas ashmem, capacité de recadrer les images autour de n’importe quel point, redimensionnement JPEG à l’aide de ressources natives, support des images JPEG progressives. |
![]() |
|
|---|---|
| Taille | 121 Ko |
| Facilité d’utilisation | élevée |
| Vitesse de téléchargement web | élevée |
| Vitesse de téléchargement depuis le cache | moyenne |
| Fonctionnalités de transformation intégrées | ensemble d’opérations de base |
| Outils supplémentaires | Absent. |
![]() |
|
|---|---|
| Taille | 440 Ko |
| Facilité d’utilisation | élevée |
| Vitesse de téléchargement web | Légèrement inférieure en raison du long traitement de mise en cache |
| Vitesse de téléchargement depuis le cache | élevée |
| Fonctionnalités de transformation intégrées | Ensemble de base plus arrondi |
| Outils supplémentaires | Chargement d’une image à partir d’une vidéo et GIF, utilisation de tout type de modèle, API flexible avec possibilité de connecter n’importe quelle pile réseau. |
![]() |
|
|---|---|
| Taille | 500 Ko |
| Facilité d’utilisation | moyenne |
| Vitesse de téléchargement web | élevée |
| Vitesse de téléchargement depuis le cache | élevée |
| Fonctionnalités de transformation intégrées | Capacités de transformation étendues, mais avec des limitations |
| Outils supplémentaires | Stockage des images non pas dans le tas Java, mais dans le tas ashmem, capacité de recadrer les images autour de n’importe quel point, redimensionnement JPEG à l’aide de ressources natives, support des images JPEG progressives. |
Ainsi, pour 2020, Picasso, Glide et Fresco sont les bibliothèques les plus populaires pour le téléchargement d’images dans les applications Android. Chacune d’entre elles a ses spécificités d’utilisation des outils avancés, notamment la mise en cache et la transformation d’images. Picasso, avec son approche minimaliste, fonctionne bien avec les opérations d’images simples, mais offre des options de personnalisation limitées. Glide est un leader incontesté parmi les téléchargeurs Android, offrant des fonctionnalités puissantes et une interface intuitive pour leur mise en œuvre. L’approche innovante de Fresco permet des gains de performance, mais complique considérablement l’implémentation de la mise en cache et de la transformation d’images.


