Glide est une librairie Android Open Source de gestion du chargement et de l’affichage d’images pour vos applications mobiles.
Glide est simple à prendre en main, facile d’utilisation et propose de nombreuses fonctionnalités... Elle vous fera économiser du temps et de l’énergie dans tous vos développements !
La première chose à faire est d’intégrer Glide à votre projet. Pour cela rien de plus simple.
Si vous utilisez Maven :
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>glide</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>compiler</artifactId>
<version>4.11.0</version>
<optional>true</optional>
</dependency>
Si vous utilisez Gradle :
repositories {
google()
jcenter()
}
dependencies {
implementation ’com.github.bumptech.glide:glide:4.11.0’
annotationProcessor ’com.github.bumptech.glide:compiler:4.11.0’
}
Glide a ensuite besoin d’une ou deux permissions pour fonctionner correctement. Rajoutez donc les lignes suivantes dans votre Manifest.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your.package.name"
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application>
...
</application>
</manifest>
Maintenant que vous savez à quoi sert Glide et comment l’intégrer dans votre projet, il est temps de rentrer dans le vif du sujet et de commencer à coder !
Glide.with(context)
.load(image)
.into(view)
Voilà c’est fini !
Bon ok je vous explique.
On commence avec Glide.with(context)
.
C’est le point de départ de toute utilisation de Glide. La méthode static .with()
crée un objet RequestManager
lié au cycle de vie du paramètre passé.
Il existe plusieurs versions de cette méthode .with(context)
, .with(activity)
, .with(fragment)
et .with(view)
, utilisez celle dont le cycle de vie vous convient le mieux.
On arrive ensuite à la méthode .load()
. C’est elle qui s’occupe d’aller chercher l’image à afficher. Plusieurs types de paramètres peuvent lui être passés, les plus courants sont :
R.drawable.src
)File(app/src/main/res/etc)
)https://homepages.cae.wisc.edu/~ece533/images/baboon.png
)Enfin .into()
indique à Glide où il doit afficher l’image qu’il vient de charger. Il s’agira le plus souvent d’une ImageView
AndroidAndroid est un système d'exploitation mobile basé sur Linux. classique, mais nous verrons plus tard des cas plus spécifiques.
A noter que le chargement factuel de l’image ne se fait pas à l’appel de .load()
mais à l’appel de .into()
.
D’ailleurs, pas la peine de vous casser la tête avec les Threads ! Glide gère lui-même. Il effectue tous ses calculs sur un Thread secondaire pour ne revenir sur le principal que pour l’affichage.
A partir d’ici, je dois vous parler de l’objet RequestOptions
.
Basiquement, toutes les options que nous allons voir par la suite peuvent être directement appliquées au RequestBuilder
retourné par la méthode .load()
.
Glide.with(context)
.load(image)
.option1()
.option2()
.into(view)
Les options se situent bien entre .load()
et .into()
.
Mais, si vous comptiez appliquer les mêmes options à plusieurs images, il peut être un peu redondant de toutes les appliquer à chaque fois.
C’est pour cela qu’existe le RequestOptions
.
val options = RequestOptions()
.option1()
.option2()
...
Glide.with(context)
.load(image1)
.apply(options)
.into(view1)
...
Glide.with(context)
.load(image2)
.apply(options)
.into(view2)
Grâce à la méthode .apply()
, on applique d’un coup toutes les options du RequestOptions
et celui-ci pourra être utilisé à plusieurs reprises.
Le premier type d’option proposé par Glide sont les Transformations. Ce sont différentes modifications graphiques appliquées à l’image avant qu’elle ne s’affiche.
Pour cela on utilise la méthode .transform()
.
Glide.with(context)
.load(image)
.transform(transformation)
.into(view)
Par défaut, Glide vous propose trois transformations pré-créées : CenterCrop
, FitCenter
et CircleCrop
.
A noter que ces trois transformations ont chacune leur propre méthode : .centerCrop()
, .fitCenter()
et .circleCrop()
, pas besoin donc de passer par .transform()
.
Cette première transformation agrandit l’image jusqu’à ce que celle-ci occupe tout son contenant de manière centrée. Puis, les bouts qui dépassent sont découpés. Cette transformation est donc à préconiser dans le cas de grandes images ne contenant pas d’informations essentielles et pouvant être rognées si besoin (ex: Background).
Glide.with(context)
.load(url)
.centerCrop()
.into(view)
ou :
Glide.with(context)
.load(url)
.transform(CenterCrop())
.into(view)
``` ![centerCrop-min.png](https://assets.axopen.com/assets/uploads/center_Crop_min_0e860ecabb.png)
#### FitCenter
La transformation `FitCenter` est l’exacte inverse de la première. Plutôt que de rogner les bouts d’une image, elle va au contraire ajouter des bandes blanches (ou noires) au besoin afin de remplir le conteneur.
Cette transformation est donc à préconiser dans le cas d’images importantes ne pouvant être rognées.
```kotlin
Glide.with(context)
.load(url)
.fitCenter()
.into(view)
ou :
Glide.with(context)
.load(url)
.transform(FitCenter())
.into(view)
``` ![fitCenter.png](https://assets.axopen.com/assets/uploads/fit_Center_a02bdaf656.png)
#### CircleCrop
Cette dernière transformation a en fait deux effets. Elle commence par effectuer un `CenterCrop` à notre image, puis applique un masque rond au résultat.
```kotlin
Glide.with(context)
.load(url)
.circleCrop()
.into(view)
ou :
Glide.with(context)
.load(url)
.transform(CircleCrop())
.into(view)
Si les quelques transformations vues ci-dessus ne vous suffisent pas, il est tout à fait possible d’en créer par vous-mêmes.
Pour cela, il vous faudra implémenter l’interface Transformation
dans une nouvelle classe.
En réalité, pour une image simple, étendre la classe abstraite BitmapTransformation
suffira largement.
class MyCustomTransformation : BitmapTransformation() {
companion object {
private val ID: String = "com.axopen.glide.mycustomtransformation"
private val ID_BYTES = ID.toByteArray(Charset.forName("UTF-8"))
}
override fun transform(pool: BitmapPool,
toTransform: Bitmap,
outWidth: Int,
outHeight: Int): Bitmap {
return toTransform
}
override fun equals(o: Object) {
return o is MyCustomTransformation
}
override fun hashCode() {
return ID.hashCode()
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update(ID_BYTES)
}
}
Notez bien que toute transformation custom doit implémenter les méthodes .equals()
, .hashCode()
et .updateDiskCacheKey()
. De plus, celles-ci doivent intégrer dans leur logique les potentiels arguments passés en constructeur de votre classe.
Concernant la méthode .transform()
, c’est elle qui doit retourner la nouvelle Bitmap, après modification. L’argument toTransform
étant bien entendu l’image de base.
Une fois votre transformation custom créée, vous pouvez l’utiliser comme n’importe quelle autre.
Glide.with(context)
.load(url)
.transform(MyCustomTransformation())
.into(view)
Par défaut, l’ajout successif de transformations ne prend en compte que la dernière.
Glide.with(context)
.load(url)
.fitCenter()
.transform(MyCustomTransformation())
.circleCrop()
.into(view)
Ce code ignore les premiers fitCenter
et MyCustomTransformation
pour n’appliquer que le dernier circleCrop
.
Pour remédier à cela il existe une solution toute simple : utiliser la méthode .transforms()
(notez le ’s’ à la fin). Celle-ci prend en paramètres plusieurs transformations et les applique successivement (dans l’ordre dans lequel on lui a présentées).
Glide.with(context)
.load(url)
.transfoms(FitCenter(), MyCustomTransformation())
.into(view)
Une autre solution consiste à créer un objet MultiTransformation
et à simplement le donner à notre méthode .transform()
en tant que transformation composite.
Glide.with(context)
.load(url)
.transfom(MultiTransformation(FitCenter(), MyCustomTransformation()))
.into(view)
Glide propose trois options afin de gérer au mieux les différents cas d’erreurs :
Un placeholder est une image temporaire, en attendant que la vraie image soit prête à être affichée.
On utilise pour ça la méthode .placeholder()
.
Glide.with(context)
.load(url)
.placeholder(R.drawable.placeholder)
.into(view)
Un placeholder ne peut être qu’une ressource locale.
Attention, les placeholder sont chargés sur le Main Thread. Évitez donc les images trop lourdes.
Comme son nom l’indique, la méthode .error()
définit quelle image sera affichée en cas d’erreur lors du chargement de celle attendue.
Glide.with(context)
.load(null)
.error(R.drawable.error)
.into(view)
Le cas d’erreur le plus courant est l’absence de connexion Internet lors d’un chargement par URLUniform Ressource Locator.
Enfin, le fallback (grâce à la méthode .fallback()
) ne couvre qu’un cas bien particulier : celui où null
est passé à la méthode .load()
.
Glide.with(context)
.load(url)
.fallback(R.drawable.fallback)
.into(view)
Petit diagramme pour expliciter l’ordre et les conditions d’affichage de chacun.
Ce que je ne vous ai pas dit au début à propos de la méthode .into()
c’est que, non seulement elle définit où l’image doit s’afficher, mais elle vous renvoie aussi un objet Target
(c’est une interface en réalité).
Dans la grande majorité des cas, vous n’aurez pas besoin de récupérer cet objet.
Mais, un cas en particulier peut vous y contraindre : si vous souhaiter charger plusieurs images dans le même conteneur.
val target = Glide.with(context)
.load(url)
.into(view)
...
Glide.with(context)
.load(secondUrl)
.into(target)
Comme vous le voyez, .into()
peut aussi prendre en argument une Target
. Dans ce cas, Glide se charge lui-même d’annuler la première requête (si celle-ci n’était pas terminée) et de libérer les ressources mémoire.
La deuxième utilité de la Target
est de pouvoir utiliser la méthode .clear()
.
Glide.with(context)
.clear(target)
Cela va annuler toute requête sur cette Target
et libérer les ressources mémoire.
Par défaut, Glide appelle cette méthode de lui-même à la fin du cycle de vie de l’élément passé à .with()
(Activity
, Fragment
, etc.). Vous n’avez donc pas à libérer vous-même les ressources à chaque fois.
Si Glide est aussi performant, c’est aussi grâce à sa gestion de la mémoire et ses mises en cache.
Nativement, Glide utilisera sa propre stratégie pour estimer où, quand et comment mettre en cache les ressources utilisées, aussi bien locales que distantes.
Cependant, il vous donne aussi la possibilité de changer de stratégie selon vos besoins grâce à la méthode .diskCacheStrategy()
. Les valeurs possibles sont :
Glide.with(context)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(view)
De plus, Glide vous permet d’affiner vos requêtes grâce aux options suivantes :
.onlyRetrieveFromCache()
: N’affichera l’image que si celle-ci est déjà en cache.Glide.with(context)
.load(url)
.onlyRetrieveFromCache(true)
.into(view)
.skipMemoryCache()
: Cette ressource ne sera pas sauvée en cache.Glide.with(context)
.load(url)
.skipMemoryCache(true)
.into(view)
Une dernière fonctionnalité bien pratique de Glide est de pouvoir sauvegarder sur votre smartphone les images téléchargées. Vous n’êtes même pas obligé de les afficher, vous pouvez simplement utiliser Glide comme module de sauvegarde.
Pour cela, il vous faut d’abord rajouter la méthode .asBitmap()
qui va dire à votre RequestManager
d’interpréter votre ressource comme une Bitmap (défaut : Drawable).
Puis simplement passer à .into()
une Target
custom.
Glide.with(context)
.asBitmap()
.load(url)
.into(new SimpleTarget<Bitmap>() {
override fun onResourceReady(Bitmap resource,Transition<? super Bitmap> transition) {
save(resource);
}
})
La méthode .save()
étant votre logique de sauvegarde.
Glide est l’une des meilleures, si ce n’est LA meilleure, librairie Android de chargement d’images distantes ou locales. Sa versatilité et sa simplicité sont ses deux plus gros atouts, sans parler de ses performances.
Bref, je ne peux que vous la conseiller dès que vous souhaitez utiliser des ressources Web dans votre application.
Et pour aller encore plus loin, je vous conseille la doc officielle de Glide et bien sûr, sa Javadoc.
Lorsque l’on possède deux datacenters différents, il n’est pas possible de migrer facilement une VM d’un datacenter à un autre directement avec un vSphere.
La digitalisation de l’industrie accélère de plus en plus. Longtemps laissée de côté car jugée trop complexe, la mobilité des agents sur le terrain commence à être prise en compte dans les plans de transformation digitale des entreprises industrielles.
Les tests E2E, c’est quoi ? Définition, implémentation et retour d’expériences des librairies de tests E2E !