
Gérer vos médias en Java
Bonjour amis de Place4Geek.
Je vous propose aujourd’hui un tutoriel sur la gestion de vos ressources multimédia en Java. En effet, lorsqu’on développe des applications un peu poussez (je pense ici aux jeux), il est nécessaire de ne pas recharger en permanence ses ressources depuis le disque.
Plutôt que d’associer la ressource à votre classe directement, il peut être judicieux de charger toutes vos ressources au lancement de l’application et d’y accéder par la suite au travers d’une simple méthode sur une classe. C’est donc ce “RessourceManager” que je vais vous présenter ici.
La classe RessourceManager
C’est donc cette classe qui va s’occuper de charger en mémoire toutes nos ressources. Que ce soit des sons, des images ou autant d’autre que vous souhaiterez.
Pour ce tutoriel, nous allons supposer que nous avons des images et des sons à charger uniquement.
Voici comme se compose notre classe :
- c’est un singleton : une unique instance sera lancée durant toute l’exécution du programme
- elle contiendra une HashMap par type de média
- elle aura une méthode de chargement par type de média
- elle fournira une méthode d’accès par type de média
Cela est peut-être un peu flou, c’est pourquoi le code de base de la classe est fournis ci-dessous :
[spoiler]
package test; import java.awt.Image; import java.io.File; import java.util.HashMap; public class RessourceManager { private static final String CHEMIN_IMAGE = "/ressources/image/"; private static final String CHEMIN_SONS = "/ressources/sound/"; private static RessourceManager instance = null; private HashMap<String, Image> mapImages; private HashMap<String, File> mapSons; public static RessourceManager getInstance(){ if(instance == null) instance = new RessourceManager(); return instance; } private RessourceManager(){ mapImages = new HashMap<String, Image>(); mapSons = new HashMap<String, File>(); } public void loadImages(){ } public void loadSons(){ } public Image getImage(String identifier){ return null; } public File getSons(String identifier){ return null; } }
[/spoiler]
Alors maintenant deux contenu de code seront disponible, l’un si vos ressources sont contenues dans le jar (ce sera une méthode très lourde), une autre si les ressources sont en dehors du jar. Allez on y va.
Chargement méthode 1 : Ressources dans le jar
Cette méthode de chargement est, selon moi, très lourde, car il faudra écrire le code de chargement de chaque ressource une par une. En revanche, lorsque vous distribuez votre application, un seul fichier est à fournir, pas besoin de le décompresser ou autre, il est prêt à être exécuter.
Voici ce que ça donne, vous comprendrez beaucoup mieux comment cela fonctionne.
[spoiler]
public void loadImages(){
Class loader = this.getClass().getClassLoader().getClass();
System.out.println(new ImageIcon(loader.getResource(CHEMIN_IMAGE+"monImage1.png").getPath()));
mapImages.put("monImage1", new ImageIcon(loader.getResource(CHEMIN_IMAGE+"monImage1.png")).getImage());
mapImages.put("monImage2", new ImageIcon(loader.getResource(CHEMIN_IMAGE+"monImage2.png")).getImage());
mapImages.put("monImage3", new ImageIcon(loader.getResource(CHEMIN_IMAGE+"monImage3.png")).getImage());
mapImages.put("monImage4", new ImageIcon(loader.getResource(CHEMIN_IMAGE+"monImage4.png")).getImage());
mapImages.put("monImage5", new ImageIcon(loader.getResource(CHEMIN_IMAGE+"monImage5.png")).getImage());
}
public void loadSons(){
Class loader = this.getClass().getClassLoader().getClass();
try {
mapSons.put("monSon", new File(loader.getResource(CHEMIN_SONS + "monSon.mp3").toURI()));
mapSons.put("monSon2", new File(loader.getResource(CHEMIN_SONS + "monSon2.mp3").toURI()));
mapSons.put("monSon3", new File(loader.getResource(CHEMIN_SONS + "monSon3.mp3").toURI()));
mapSons.put("monSon4", new File(loader.getResource(CHEMIN_SONS + "monSon4.mp3").toURI()));
mapSons.put("monSon5", new File(loader.getResource(CHEMIN_SONS + "monSon5.mp3").toURI()));
} catch (URISyntaxException ex) {
//traitement de l'exception comme vous le voulez
}
}
[/spoiler]
Bon quelques explications s’imposent :
Class loader = this.getClass().getClassLoader().getClass();
On charge le ClassLoader et on récupère sa classe (en gros qui est à la racine de notre jar) afin de charger les images depuis cette dernière.
mapImages.put("monImage1", new ImageIcon(loader.getResource(CHEMIN_IMAGE+"monImage1.png")).getImage());
Cette ligne relativement complexe, est en fait l’ajout de l’image dans notre map. L’identifiant est ici “monImage1”, ce qui permettra d’y accéder par la suite de manière unique et simple.
L’autre partie de la méthode “put” contient notre image fraichement chargée en mémoire. A partir du loader, on récupère la ressource ayant pour chemin : CHEMIN_IMAGE+”monImage1.png”.
Pour le son c’est sensiblement pareil, ce qui change, c’est que j’utilise des File à la place des Image pour la map, c’est donc relativement simple à comprendre si vous avez saisie le chargement des images.
Chargement méthode 2 : Ressources à l’extérieur du jar
Ici, on suppose que nos ressources sont contenues dans des dossiers en dehors du jar, ainsi on peut exécuter facilement un parcours et un ajout automatique des ressources dans notre ressource manager.
Voici le code de chargement pour les images :
[spoiler]
public void loadImages(){
String path = this.getClass().getClassLoader().getResource("").getPath();
File folder = new File(path+CHEMIN_IMAGE);
for(File f : folder.listFiles()){
if(f.isFile()){
String name = f.getName();
mapImages.put(name, new ImageIcon(f.getPath()).getImage());
}
}
}
public void loadSons(){
String path = this.getClass().getClassLoader().getResource("").getPath();
File folder = new File(path+CHEMIN_SONS);
for(File f : folder.listFiles()){
if(f.isFile()){
String name = f.getName();
mapSons.put(name, f);
}
}
}
[/spoiler]
Tout de suite c’est vachement plus simple.
Bon parce que je suis sympa et que vous avez eu le courage (ou pas) de lire jusque là , je vais remettre une petite couche d’explications.
String path = this.getClass().getClassLoader().getResource("").getPath();
On récupère grâce à cette ligne l’endroit où se trouve notre jar sur le disque dur. Mais pour quoi donc qu’est-ce que faire ? C’est simple, c’est pour trouver le dossier des ressource, vous savez grâce à notre petite variable magique : CHEMIN_IMAGE ou CHEMIN_SONS.
File folder = new File(path+CHEMIN_SONS);
Quelle ligne magnifique, en fait on récupère ici le dossier de nos ressources, ici le dossier des sons. Maintenant, on va le parcourir hein, et puis on va pouvoir charger les image directement sans rien écrire de fatiguant avec des copier/coller frénétique.
for(File f : folder.listFiles()){
}
Cette structure de boucle en Java est récente, depuis la version 5 il me semble, mais elle est très pratique.
En effet, on dit au programme ici, que pour chaque fichier qu’il trouve dans la collection folder.listFiles() (qui liste les fichiers et dossier contenus dans un dossier) il va exécuter une boucle. C’est un moyen plus rapide d’écrire un pseudo Itérateur. Bref, passons les détails et voyons le chargement maintenant.
if(f.isFile()){
String name = f.getName();
mapSons.put(name, f);
}
Dans un premier temps, on vérifie que le fichier est bien un fichier, et non un dossier. Si c’est le cas, on récupère son nom qui servira de clé et ensuite, on l’insère dans notre map.
C’est simple n’est-ce pas ? Moi qui suis un grand fainéant, cette méthode me sert dans tous les jeux que je développe. Bon après, faut bien connaître le nom de ses fichiers pour la suite.
A mais oui c’est vrai, c’est pas encore fini, il faut que je vous parle de comment récupérer vos ressources maintenant. Ha bah tiens, c’est le titre de la partie suivante !
Comment récupérer vos ressources ?
Toi, oui toi … geek d’un jour geek toujours ! Tu vas comprendre la puissance des map maintenant.
Une Map est une collection qui associe une valeur à une clé. Dans notre cas, les clés sont les noms de nos fichiers, les valeurs, nos ressources (image, son …). Te souviens-tu l’été dernier de ce morceau de code :
public Image getImage(String identifier){
return null;
}
public File getSons(String identifier){
return null;
}
Bien évidemment, il n’était pas complet, mais je préférais voir le plus compliqué avant et que tu puisses te reposer vers la fin. Ce sont ces deux méthodes qui vont nous permettre de récupérer nos ressources qu’importe le lieu et qu’importe l’endroit ! Voyons voir le contenu (très simple) de ces dernières.
public Image getImage(String identifier){
if(mapImages.containsKey(identifier))
return mapImages.get(identifier);
else
return null;
}
public File getSons(String identifier){
if(mapSons.containsKey(identifier))
return mapSons.get(identifier);
else
return null;
}
Pour l’une et l’autre, ça se passe de la même façon, on regarde si la Map contient la clé passée en paramètre, si c’est le cas, on renvoi l’objet associé, sinon on retourne null.
De ce fait, voici comment utiliser vos ressources depuis les autres classes :
RessourceManager.getInstance().getImage("monImage1");
Vous avez le droit d’avouer que c’est simple. Bon certes on injecte une dépendance supplémentaire dans nos paquetages, mais bon, dans le cas d’un MVC, pas de problèmes ^^.
Ha oui j’avais dit que je fournirais le code complet à la fin du tuto … c’était un mensonge, si tu as mal lu, tu devras tout relire …. mouahahahaha punition suprême.
Voilà , ce premier tutoriel de programmation Java est terminé. Je compte en refaire d’autre, il faut que je trouve l’inspiration et le temps mais si vous avez des remarques à faire sur ce premier tuto, merci de laisser un commentaire ou bien d’envoyer un mail à contact@place4geek.com
Allez, ciao les zamis geek !
je vous souhaite bon courage les zamis !! j’espère que ce site fera un malheur dans quelques temps . vous êtes passionner , …. et les premier articles sont prometteurs.