Une application Android moderne est difficile à imaginer sans chargeurs d’images. Ils prennent en charge le travail fastidieux de chargement asynchrone, de traitement des erreurs, d’affichage des espaces réservés, de mise en cache et de transformation des images. L’automatisation des processus dispense le développeur du besoin de « réinventer la roue », lui donnant ainsi la possibilité de se concentrer sur l’écriture de la logique métier plutôt que sur du code répétitif. En 2021, les bibliothèques Picasso, Glide et Fresco étaient les plus couramment utilisées dans les projets Android.
Chaque développeur Android a généralement un choix préféré. Voici notre analyse pour vous aider à identifier la meilleure option.
de Square est conçu dans l’idée d’apporter une simplicité et une clarté maximales au travail. Ces objectifs se reflètent dans la capacité à maintenir une taille d’APK réduite – Picasso n’ajoute que 121 Ko et 849 de ses méthodes au projet. Il y a deux faces à chaque médaille, et cet espace limité affecte négativement la fonctionnalité, qui ne couvre que les opérations de base avec les images. Toute la documentation de la bibliothèque tient facilement sur une seule page web.
de Bump Tech est construit sur des principes différents : une fonctionnalité puissante et un riche arsenal pour la gestion des images. Par conséquent, Glide augmente la taille des applications d’au moins 440 Ko et 2678 méthodes. Pourtant, en retour, le développeur obtient une bibliothèque flexible et conviviale pour le chargement asynchrone des images.
de Facebook met l’accent sur la productivité et une utilisation judicieuse des ressources du système d’exploitation. Par exemple, en offrant une opportunité plutôt inhabituelle aux développeurs d’utiliser un SimpleDraweeView spécial pour afficher des images.
Il est maintenant temps de différencier les diverses façons d’ajouter de l’interactivité à l’affichage des images avec Picasso, Glide et Fresco. Cet article couvrira trois domaines : l’effet de fondu, l’affichage d’une barre de progression pendant le chargement, et la rotation de l’image une fois le chargement terminé.
Effet de fondu
Dans Picasso, le support des animations n’est pas sa fonctionnalité la plus robuste, et dans la plupart des cas, les utilisateurs doivent ajouter eux-mêmes le code de l’effet d’animation. Cependant, le fondu natif est déjà implémenté. Toutes les images qui ne sont pas chargées depuis la RAM apparaissent avec cette animation. Il est impossible d’influencer sa durée ou d’autres caractéristiques. La seule option est d’activer/désactiver l’effet.
Picasso
.get()
.load(imageUrl)
.noFade()
.into(test_imageview)
Glide 4 permet de définir le fondu en utilisant la fonction transition(). Elle peut prendre en argument une instance de la classe DrawableTransitionOptions, qui définit les paramètres pour passer à une nouvelle image. En particulier, Glide permet de définir le temps de transition. Dans l’exemple ci-dessous, nous définissons le temps de l’effet de fondu à 5 secondes.
Glide.with(this)
.load(imageUrl)
.transition(DrawableTransitionOptions.withCrossFade(5))
.into(test_imageview)
Il faut également tenir compte du fait que le fondu dans Glide a 2 modifications : les fondus croisés désactivés ou activés. Dans le premier mode, une nouvelle image apparaît progressivement par-dessus l’ancienne. Cela permet d’économiser considérablement les ressources, mais cela peut poser problème si la nouvelle image a des pixels transparents ou une taille inférieure à l’ancienne. Dans ce dernier cas, 2 animations sont traitées de manière cohérente : d’abord, l’ancienne image disparaît progressivement, suivie par l’affichage progressif d’une nouvelle. Cela donne un bel effet mais nécessite beaucoup de ressources de l’OS. Sur de grandes listes, le fondu croisé peut être un véritable problème. Vous pouvez l’activer/désactiver à l’aide des paramètres de transition.
val factory = DrawableCrossFadeFactory
.Builder()
.setCrossFadeEnabled(true)
.build()
Glide.with(this)
.load(imageUrl)
.transition(withCrossFade(factory))
.into(test_imageview)
Si vous le souhaitez, Glide peut définir d’autres animations lors du passage à une nouvelle image. Alternativement, une nouvelle image peut aller vers la gauche ou s’agrandir d’une petite taille à sa taille d’origine. Pour mettre en œuvre cette approche, vous devez décrire l’animation dans un fichier xml, créer une instance de la classe GenericTransitionOptions avec celle-ci comme argument du constructeur, et l’ajouter à la fonction transition().
Cette animation décrit la transition vers la gauche.
<!--?xml version="1.0" encoding="utf-8"?-->
La gestion du fondu avec Fresco est beaucoup plus simple par rapport aux autres bibliothèques. Cela peut se faire dans la disposition xml…
…ainsi que dans le code de l’Activity / Fragment.
val builder = GenericDraweeHierarchyBuilder(getResources())
val jerarquía = constructor
.setFadeDuration(3000)
.build()
fresco_imageview.setHierarchy(hierarchy)
Dans le même temps, Fresco ne prend en charge qu’une option de fondu croisé « toujours activé », ce qui peut entraîner une consommation accrue des ressources par l’application.
Barres de progression de chargement
Lors du téléchargement d’images volumineuses ou en cas de connexion Internet instable, une barre de progression peut s’avérer utile : soit une barre infinie, soit une barre affichant l’état du téléchargement.
Lorsque vous utilisez Picasso, vous ne pouvez implémenter que la première option, moins exigeante. Elle peut être créée soit en utilisant la fonction placeholder(), soit en surchargeant la classe Target.
Dans le premier cas, nous créons une animation en xml.
<!--?xml version="1.0" encoding="utf-8"?-->
Ensuite, il suffit de l’ajouter comme espace réservé.
Picasso
.get()
.load(imageUrl)
.placeholder( R.drawable.infinitive_progressbar)
.into(test_imageview)
Dans la seconde méthode, nous ajoutons une barre de progression à la mise en page par-dessus l’ImageView, puis nous créons notre propre classe qui contrôlera le chargement de l’image.
class ProgressTarget(imageView: ImageView, progressBar: ProgressBar) :
com.squareup.picasso.Target {
private val ivRef: WeakReference
private val progressRef: WeakReference
init {
ivRef = WeakReference(imageView)
progressRef = WeakReference(progressBar)
}
override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {
val imageView = ivRef.get()
imageView?.setImageBitmap(bitmap)
val progressBar = progressRef.get()
progressBar?.setVisibility(View.GONE)
}
override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) {
val imageView = ivRef.get()
imageView?.setImageDrawable(errorDrawable)
val progressBar = progressRef.get()
progressBar?.setVisibility(View.GONE)
}
override fun onPrepareLoad(placeHolderDrawable: Drawable) {
val imageView = ivRef.get()
imageView?.setImageDrawable(placeHolderDrawable)
val progressBar = progressRef.get()
progressBar?.setVisibility(View.VISIBLE)
}
}
Son utilisation est extrêmement simple : créez une instance de ProgressTarget avec les liens nécessaires vers ImageView et ProgressBar, utilisez-la comme argument de la fonction into(). La dernière étape consiste à ajouter l’instance ProgressTarget comme balise à l’ImageView pour la protéger du garbage collector.
val target = ProgressTarget(test_imageview, test_progressbar)
Picasso
.get()
.load(imageUrl)
.into(target)
test_imageview.setTag(target)
Glide offre une approche plus complète pour la création de barres de progression. L’approche est la même qu’avec Picasso :
- ajouter une animation à la fonction placeholder (en option : utiliser une image gif à la place d’une animation xml) ;
- étendre la classe RequestListener.
De plus, la flexibilité des paramètres de cette bibliothèque vous permet d’obtenir l’état de chargement de l’image et d’afficher non seulement un cache-mis en place animé mais un contenu plus informatif. Pour ce faire, vous devez surcharger les paramètres de base dans GlideModule. La version la plus qualitative d’une telle solution a été proposée par Róbert Papp dans son OkHttpProgressGlideModule.
Sans aucun doute, Fresco offre le moyen le plus simple de résoudre le problème des barres de progression. Pour créer une barre de progression infinie, il suffit d’ajouter une ligne à la mise en page xml…
fresco:progressBarImage="@drawable/spinner"
...ou faites-le depuis le code de l'Activity / Fragment
fresco_imageview.hierarchy.setProgressBarImage(AutoRotateDrawable(icon, 1000))
L’ajout d’un indicateur de téléchargement ne demande pas non plus beaucoup d’efforts. Créez et personnalisez simplement un ProgressBarDrawable si nécessaire.
val progressBarDrawable = ProgressBarDrawable()
progressBarDrawable.setColor(Color.YELLOW)
progressBarDrawable.setBackgroundColor(Color.BLUE)
progressBarDrawable.setRadius(2)
fresco_imageview.getHierarchy().setProgressBarImage(progressBarDrawable)
Rotation de l’image
L’ajout d’une animation après le chargement de l’image est une option rare mais tout à fait possible. Sans plus attendre, plongeons dans les spécificités d’implémentation pour chacune des 3 bibliothèques.
Picasso dispose d’une classe Callback qui vous permet d’exécuter la logique nécessaire après le chargement de l’image. Pour appliquer une animation, nous devons :
- déterminer l’animation dont nous avons besoin au format xml,
- la charger dans l’Activity / Fragment,
- créer un objet Callback,
- y placer le code de reproduction de l’animation,
- ajouter cet objet comme argument à la fonction into().
<!--?xml version="1.0" encoding="utf-8"?-->
val rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate)
val callback = object : Callback {
override fun onSuccess() {
test_imageview.startAnimation(rotateAnimation)
}
override fun onError(e: java.lang.Exception?) {
Log.e(TAG, e?.message)
}
}
Picasso.get().load(imageUrl).into(test_imageview, callback)
Dans Glide, vous pouvez utiliser la fonction listener() pour reproduire un scénario similaire, qui prend un objet de la classe RequestListener comme argument.
Glide.with(this)
.load(imageUrl)
.listener(objeto : RequestListener{
override fun onLoadFailed(
e: GlideException?
modelo: Cualquiera?
target: com.bumptech.glide.request.target.Target?
isFirstResource: Boolean
): Booleano {
Log.e(TAG, e?.mensaje)
devolver false
}
override fun onResourceReady(
recurso: Drawable?
modelo: Cualquiera?
target: com.bumptech.glide.request.target.Target?
dataSource: DataSource?
isFirstResource: Booleano
): Booleano {
test_imageview.startAnimation(rotateAnimation)
return false
}
})
.into(test_imageview)
Dans Fresco, la construction de l’animation finale est un peu différente. En plus de créer et de charger le code d’animation, vous devez également créer 2 objets : BaseControllerListener (répond à l’état de chargement de l’image) et DraweeController (contrôle les requêtes et renvoie). Le résultat global sera identique aux exemples précédents avec Picasso et Glide.
val frescoListener = object: BaseControllerListener() {
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
fresco_imageview.startAnimation(rotateAnimation)
}
}
val controller = Fresco.newDraweeControllerBuilder()
.setUri(imageUrl)
.setControllerListener(frescoListener)
.build()
fresco_imageview.setController(controller)
En résumé
Pour conclure ce qui précède, voici un tableau comparatif des trois bibliothèques :
| Critère | ![]() |
![]() |
![]() |
|---|---|---|---|
| Prise en charge de l’effet de fondu | Intégré | Intégré | Intégré |
| Contrôle de l’effet de fondu | Option d’activation/désactivation | Ajuster la durée, l’approche du fondu croisé, définir différentes animations pour la transition entre les images | Activation/désactivation, ajustement de la durée |
| Prise en charge des barres de progression | Aucune. Une vue de progression séparée est nécessaire | Aucune. Une vue de progression séparée est nécessaire/redéfinir GlideModule | Disponible. Possibilité de créer différents types de barres de progression dans la mise en page xml et dans l’Activity / Fragment. |
| Création d’une barre de progression avec pourcentages | Impossible | Pris en charge lors de l’utilisation de la bibliothèque OkHttp. Nécessite de redéfinir GlideModule | Pris en charge par la bibliothèque |
| Mécanisme d’affichage de l’animation finale | Callback | RequestListener | BaseControllerListener |
![]() |
|
|---|---|
| Prise en charge de l’effet de fondu | Intégré |
| Contrôle de l’effet de fondu | Option d’activation/désactivation |
| Prise en charge des barres de progression | Aucune. Une vue de progression séparée est nécessaire |
| Création d’une barre de progression avec pourcentages | Impossible |
| Mécanisme d’affichage de l’animation finale | Callback |
![]() |
|
|---|---|
| Prise en charge de l’effet de fondu | Intégré |
| Contrôle de l’effet de fondu | Ajuster la durée, l’approche du fondu croisé, définir différentes animations pour la transition entre les images |
| Prise en charge des barres de progression | Aucune. Une vue de progression séparée est nécessaire/redéfinir GlideModule |
| Création d’une barre de progression avec pourcentages | Pris en charge lors de l’utilisation de la bibliothèque OkHttp. Nécessite de redéfinir GlideModule |
| Mécanisme d’affichage de l’animation finale | RequestListener |
![]() |
|
|---|---|
| Prise en charge de l’effet de fondu | Intégré |
| Contrôle de l’effet de fondu | Activation/désactivation, ajustement de la durée |
| Prise en charge des barres de progression | Disponible. Possibilité de créer différents types de barres de progression dans la mise en page xml et dans l’Activity / Fragment. |
| Création d’une barre de progression avec pourcentages | Pris en charge par la bibliothèque |
| Mécanisme d’affichage de l’animation finale | BaseControllerListener |
Ainsi, vous pouvez ajouter la possibilité d’afficher des animations dans tous les téléchargeurs d’images populaires pour les applications Android. Les bibliothèques de manipulation d’images que nous avons discutées ci-dessus peuvent être décrites de manière concise par les avantages suivants :
- Glide offre la meilleure fonctionnalité pour gérer les effets de transition
- Fresco dispose d’une bonne API pour créer et personnaliser des barres de progression
- Picasso est facile à utiliser, même pour les spécialistes débutants
Les mécanismes d’affichage de l’animation finale dans les trois bibliothèques sont similaires et donnent le même résultat.


