Cyril Mottier

“It’s the little details that are vital. Little things make big things happen.” – John Wooden

Astuce #3 : Récupérer Facilement Les Ressources

Note : l'astuce donnée dans ce post n'est pas vraiment relative à Android. C'est, en réalité, une astuce rendue possible par la flexibilité du langage Java. Néanmoins, il s'avère que cette technique est bien souvent utile et méconnue des développeurs Android.

Ne vous est-il jamais arrivé d'écrire des lignes répétitives un peu du genre de celles données ci-dessous?

1
2
3
4
5
6
7
8
9
10
11
ImageView mImageViews[] = new ImageView[100];

mImageViews[0] = new ImageView(this);
mImageViews[0] = setImageResource(R.drawable.image0);
mImageViews[1] = new ImageView(this);
mImageViews[1] = setImageResource(R.drawable.image1);
// Encore et encore les mêmes lignes ...
mImageViews[98] = new ImageView(this);
mImageViews[98] = setImageResource(R.drawable.image98);
mImageViews[99] = new ImageView(this);
mImageViews[99] = setImageResource(R.drawable.image99);

J'espère pour vous que vous n'avez jamais fait cela ! En effet, en plus de faire grossir le code compilé résultant, ce genre de code source est surtout illisible pour de futurs utilisateurs/relecteurs, sujet à erreurs (copier-coller oblige) et surtout très ennuyant à écrire. Tout bon programmeur tente, dans la mesure du possible de factoriser le code. Pour ce faire, on définit d'abord les constantes au niveau de la classe (j'ai mis trois points parce que je suis feignant et que ça n'a pas de réelle utilité de mettre la vraie suite) :

1
2
// Prepare le tableau des identifiants de ressources
private static final int IMAGE_IDS = {R.drawable.image0, R.drawable.image1, R.drawable.image2, /* ... */, R.drawable.image98, R.drawable.image99};

Il est maintenant possible de factoriser le code via une simple boucle for :

1
2
3
4
5
6
7
ImageView mImageViews[] = new ImageView[100];

final int count = IMAGES_IDS.length;
for (int i = 0; i < count; i++) {
    mImageViews[i] = new ImageView(this);
    mImageViews[i].setImageResource(IMAGES_IDS[i]);
}

Une telle méthode a l'avantage certain de minimiser le code “effectif”, d'être beaucoup plus lisible et moins dangereuse. Malheureusement, elle reste encore assez rébarbative puisque il faut créer le tableau IMAGES_IDS. Pour finir, si on souhaite ajouter de nouveaux Drawables, il faut retoucher au code du tableau IMAGES_IDS pour qu'ils soient pris en compte.

Android regroupe, de façon automatique (c'est l'outil aapt qui s'en charge) , l'intégralité des ressources dans un fichier nommé R.java. En d'autres termes, les ressources sont accessibles via le code Java par l'intermédiaire de constantes définies dans ce fichier de ressources. Pour faciliter la récupération de ressources, il est donc possible d'utiliser les Field. Le code précédent devient maintenant :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// On récupère l'ensemble des "champs" de la classe R.drawable
Field[] fields = R.drawable.class.getFields();

// Le -1 est nécessaire pour ne pas inclure l'icône de l'application
ImageView mImageViews[] = new ImageView[fields.length - 1];

int i = 0;
for (Field field : fields) {
    try {
        // Pour chaque champ, on récupère sa valeur (c'est à dire l'identifiant de la ressource)
        int currentResId = field.getInt(R.drawable.class);
        // Si cet identifiant n'est pas celui de l'icône de mon application
        if (currentResId != R.drawable.mydemo_icon) {
            mImageViews[i] = new ImageView(this);
            mImageViews[i].setImageResource(currentResId);
            i++;
        }
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

Toute méthode a ses avantages et ses inconvénients. Cette dernière ne déroge pas à la règle. Son avantage indéniable est de supprimer le code à maintenir dans le cas d'ajout ou de suppression de drawable. Lorsqu'on ajoute un nouveau drawable au projet, il est automatiquement pris en compte au prochain lancement du programme. Son inconvénient réside dans sa “globalité”. Imaginons que vous souhaitiez ne prendre un compte qu'un nombre fini (20 par exemple) des 100 drawables de votre projet. La condition d'exclusion devient énorme !.