Les ressources

Ce contenu est obsolète. Il peut contenir des informations intéressantes mais soyez prudent avec celles-ci.

Je vous ai déjà présenté le répertoire src/ qui contient toutes les sources de votre programme. On va maintenant s'intéresser à un autre grand répertoire : res/. Vous l'aurez compris, c'est dans ce répertoire que sont conservées les ressources, autrement dit les éléments qui s'afficheront à l'écran ou avec lesquels l'utilisateur pourra interagir.

Android est destiné à être utilisé sur un très grand nombre de supports différents, et il faut par conséquent s'adapter à ces supports. Imaginons qu'une application ait à afficher une image. Si on prend une petite image, il faut l’agrandir pour qu'elle n'ait pas une dimension ridicule sur un grand écran. Mais en faisant cela, l'image perdra en qualité. Une solution serait donc d'avoir une image pour les petits écrans, une pour les écrans moyens et une pour les grands écrans. C'est ce genre de précautions qu'il faut prendre quand on veut développer pour les appareils mobiles.

Un des moyens d'adapter nos applications à tous les terminaux est d'utiliser les ressources. Les ressources sont des fichiers organisés d'une manière particulière de façon à ce qu'Android sache quelle ressource utiliser pour s'adapter au matériel sur lequel s'exécute l’application. Comme je l'ai dit précédemment, adapter nos applications à tous les types de terminaux est indispensable. Cette adaptation passe par la maîtrise des ressources.

Pour déclarer des ressources, on passe très souvent par le format XML, c'est pourquoi un point sur ce langage est nécessaire.

Le format XML

Si vous maîtrisez déjà le XML, vous pouvez passer directement à la suite.

Les langages de balisage

Le XML est un langage de balisage un peu comme le HTML — le HTML est d'ailleurs indirectement un dérivé du XML. Le principe d'un langage de programmation (Java, C++, etc.) est d'effectuer des calculs, puis éventuellement de mettre en forme le résultat de ces calculs dans une interface graphique. À l'opposé, un langage de balisage (XML, donc) n'effectue ni calcul, ni affichage, mais se contente de mettre en forme des informations. Concrètement, un langage de balisage est une syntaxe à respecter, de façon à ce qu'on sache de manière exacte la structuration d'un fichier. Et si on connaît l'architecture d'un fichier, alors il est très facile de retrouver l'emplacement des informations contenues dans ce fichier et de pouvoir les exploiter. Ainsi, il est possible de développer un programme appelé interpréteur qui récupérera les données d'un fichier (structuré à l'aide d'un langage de balisage).

Par exemple pour le HTML, c'est un navigateur qui interprète le code afin de donner un sens aux instructions ; si vous lisez un document HTML sans interpréteur, vous ne verrez que les sources, pas l'interprétation des balises.

Un exemple pratique

Imaginons un langage de balisage très simple, que j'utilise pour stocker mes contacts téléphoniques :

1
Anaïs Romain Thomas Xavier

Ce langage est très simple : les prénoms de mes contacts sont séparés par une espace. Ainsi, quand je demanderai à mon interpréteur de lire le fichier, il saura que j'ai 4 contacts parce que les prénoms sont séparés par des espaces. Il lit une suite de caractères et dès qu'il tombe sur une espace, il sait qu'on va passer à un autre prénom.

On va maintenant rendre les choses plus complexes pour introduire les numéros de téléphone :

1
2
3
4
Anaïs : 1111111111
Romain: 2222222222
Thomas: 3333333333
Xavier: 4444444444

Là, l'interpréteur sait que pour chaque ligne, la première suite de caractères correspond à un prénom qui se termine par un deux-points, puis on trouve le numéro de téléphone qui se termine par un retour à la ligne. Et, si j'ai bien codé mon interpréteur, il sait que le premier prénom est « Anaïs » sans prendre l'espace à la fin, puisque ce n'est pas un caractère qui rentre dans la composition d'un prénom.

Si j'avais écrit mon fichier sans syntaxe particulière à respecter, alors il m'aurait été impossible de développer un interpréteur qui puisse retrouver les informations.

La syntaxe XML

Comme pour le format HTML, un fichier XML débute par une déclaration qui permet d'indiquer qu'on se trouve bien dans un fichier XML.

1
<?xml version="1.0" encoding="utf-8"?>

Cette ligne permet d'indiquer que :

  • On utilise la version 1.0 de XML.
  • On utilise l'encodage des caractères qui s'appelle utf-8 ; c'est une façon de décrire les caractères que contiendra notre fichier.

Je vais maintenant vous détailler un fichier XML :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<bibliotheque>
  <livre style="fantaisie">
    <auteur>George R. R. MARTIN</auteur>
    <titre>A Game Of Thrones</titre>
    <langue>klingon</langue>
    <prix>10.17</prix>
  </livre>
  <livre style="aventure">
    <auteur>Alain Damasio</auteur>
    <titre>La Horde Du Contrevent</titre>
    <prix devise="euro">9.40</prix>
    <recommandation note="20"/>
  </livre>
</bibliotheque>

L'élément de base du format XML est la balise. Elle commence par un chevron ouvrant < et se termine par un chevron fermant >. Entre ces deux chevrons, on trouve au minimum un mot. Par exemple <bibliotheque>. Cette balise s'appelle balise ouvrante, et autant vous le dire tout de suite : il va falloir la fermer ! Il existe deux manières de fermer une balise ouvrante :

  • Soit par une balise fermante </bibliotheque>, auquel cas vous pourrez avoir du contenu entre la balise ouvrante et la balise fermante. Étant donné que notre bibliothèque est destinée à contenir plusieurs livres, nous avons opté pour cette solution.
  • Soit on ferme la balise directement dans son corps : <bibliotheque />. La seule différence est qu'on ne peut pas mettre de contenu entre deux balises… puisqu'il n'y en a qu'une. Dans notre exemple, nous avons mis la balise <recommandation note="20"/> sous cette forme par choix, mais nous aurions tout aussi bien pu utiliser <recommandation>20</recommandation>, cela n'aurait pas été une erreur.

Ce type d'informations, qu'il soit fermé par une balise fermante ou qu'il n'en n'ait pas besoin, s'appelle un nœud. Vous voyez donc que l'on a un nœud appelé bibliotheque, deux nœuds appelés livre, etc.

Un langage de balisage n'a pas de sens en lui-même. Dans notre exemple, notre nœud s'appelle bibliotheque, on en déduit, nous humains et peut-être, s'ils nous lisent, vous Cylons, qu'il représente une bibliothèque, mais si on avait décidé de l'appeler fkldjsdfljsdfkls, il aurait autant de sens au niveau informatique. C'est à vous d'attribuer un sens à votre fichier XML au moment de l'interprétation.

Le nœud <bibliotheque>, qui est le nœud qui englobe tous les autres nœuds, s'appelle la racine. Il y a dans un fichier XML au moins une racine et au plus une racine. Oui ça veut dire qu'il y a exactement une racine par fichier. ;)

On peut établir toute une hiérarchie dans un fichier XML. En effet, entre la balise ouvrante et la balise fermante d'un nœud, il est possible de mettre d'autres nœuds. Les nœuds qui se trouvent dans un autre nœud s'appellent des enfants, et le nœud encapsulant s'appelle le parent.

Les nœuds peuvent avoir des attributs pour indiquer des informations. Dans notre exemple, le nœud <prix> a l'attribut devise afin de préciser en quelle devise est exprimé ce prix : <prix devise="euro">9.40</prix> pour La Horde Du Contrevent, qui vaut donc 9€40. Vous remarquerez que pour A Game Of Thrones on a aussi le nœud prix, mais il n'a pas l'attribut devise ! C'est tout à fait normal : dans l'interpréteur, si la devise est précisée, alors je considère que le prix est exprimé en cette devise ; mais si l'attribut devise n'est pas précisé, alors le prix est en dollars. A Game Of Thrones vaut donc \$10.17. Le format XML en lui-même ne peut pas détecter si l'absence de l'attribut devise est une anomalie, cela retirerait toute la liberté que permet le format.

En revanche, le XML est intransigeant sur la syntaxe. Si vous ouvrez une balise, n'oubliez pas de la fermer par exemple !

Les différents types de ressources

Les ressources sont des éléments capitaux dans une application Android. On y trouve par exemple des chaînes de caractères ou des images. Comme Android est destiné à être utilisé sur une grande variété de supports, il fallait trouver une solution pour permettre à une application de s'afficher de la même manière sur un écran 7" que sur un écran 10", ou faire en sorte que les textes s'adaptent à la langue de l'utilisateur. C'est pourquoi les différents éléments qui doivent s'adapter de manière très précise sont organisés de manière tout aussi précise, de façon à ce qu'Android sache quels éléments utiliser pour quels types de terminaux.

On découvre les ressources à travers une hiérarchie particulière de répertoires. Vous pouvez remarquer qu'à la création d'un nouveau projet, Eclipse crée certains répertoires par défaut, comme le montre la figure suivante.

L'emplacement des ressources au sein d'un projet

Je vous ai déjà dit que les ressources étaient divisées en plusieurs types. Pour permettre à Android de les retrouver facilement, chaque type de ressources est associé à un répertoire particulier. Voici un tableau qui vous indique les principales ressources que l'on peut trouver, avec le nom du répertoire associé. Vous remarquerez que seuls les répertoires les plus courants sont créés par défaut.

Type

Description

Analyse syntaxique

Dessin et image (res/drawable)

On y trouve les images matricielles (les images de type PNG, JPEG ou encore GIF) ainsi que des fichiers XML qui permettent de décrire des dessins simples (par exemple des cercles ou des carrés).

Oui

Mise en page ou interface graphique (res/layout)

Les fichiers XML qui représentent la disposition des vues (on abordera cet aspect, qui est très vaste, dans la prochaine partie).

Exclusivement

Menu (res/menu)

Les fichiers XML pour pouvoir constituer des menus.

Exclusivement

Donnée brute (res/raw)

Données diverses au format brut. Ces données ne sont pas des fichiers de ressources standards, on pourrait y mettre de la musique ou des fichiers HTML par exemple.

Le moins possible

Différentes variables (res/values)

Il est plus difficile de cibler les ressources qui appartiennent à cette catégorie tant elles sont nombreuses. On y trouve entre autre des variables standards, comme des chaînes de caractères, des dimensions, des couleurs, etc.

Exclusivement

La colonne « Analyse syntaxique » indique la politique à adopter pour les fichiers XML de ce répertoire. Elle vaut :

  • « Exclusivement », si les fichiers de cette ressource sont tout le temps des fichiers XML.
  • « Oui », si les fichiers peuvent être d'un autre type que XML, en fonction de ce qu'on veut faire. Ainsi, dans le répertoire drawable/, on peut mettre des images ou des fichiers XML dont le contenu sera utilisé par un interpréteur pour dessiner des images.
  • « Le moins possible », si les fichiers doivent de préférence ne pas être de type XML. Pourquoi ? Parce que tous les autres répertoires sont suffisants pour stocker des fichiers XML. Alors, si vous voulez placer un fichier XML dans le répertoire raw/, c'est qu'il ne trouve vraiment pas sa place dans un autre répertoire.

Il existe d'autres répertoires pour d'autres types de ressources, mais je ne vais pas toutes vous les présenter. De toute manière, on peut déjà faire des applications complexes avec ces ressources-là.

Ne mettez pas de ressources directement dans res/, sinon vous aurez une erreur de compilation !

L'organisation

Si vous êtes observateurs, vous avez remarqué sur l'image précédente que nous avions trois répertoires res/drawable/, alors que dans le tableau que nous venons de voir, je vous disais que les drawables allaient tous dans le répertoire res/drawable/ et point barre ! C'est tout à fait normal et ce n'est pas anodin du tout.

Comme je vous le disais, nous avons plusieurs ressources à gérer en fonction du matériel. Les emplacements indiqués dans le tableau précédent sont les emplacements par défaut, c'est-à-dire qu'il s'agit des emplacements qui visent le matériel le plus générique possible. Par exemple, vous pouvez considérer que le matériel le plus générique est un système qui n'est pas en coréen, alors vous allez mettre dans le répertoire par défaut tous les fichiers qui correspondent aux systèmes qui ne sont pas en coréen (par exemple les fichiers de langue). Pour placer des ressources destinées aux systèmes en coréen, on va créer un sous-répertoire et préciser qu'il est destiné aux systèmes en coréen. Ainsi, automatiquement, quand un utilisateur français ou anglais utilisera votre application, Android choisira les fichiers dans l'emplacement par défaut, alors que si c'est un utilisateur coréen, il ira chercher dans les sous-répertoires consacrés à cette langue.

En d'autres termes, en partant du nom du répertoire par défaut, il est possible de créer d'autres répertoires qui permettent de préciser à quels types de matériels les ressources contenues dans ce répertoire sont destinées. Les restrictions sont représentées par des quantificateurs et ce sont ces quantificateurs qui vous permettront de préciser le matériel pour lequel les fichiers dans ce répertoire sont destinés. La syntaxe à respecter peut être représentée ainsi : res/<type_de_ressource>[<-quantificateur 1><-quantificateur 2>…<-quantificateur N>]

Autrement dit, on peut n'avoir aucun quantificateur si l'on veut définir l'emplacement par défaut, ou en avoir un pour réduire le champ de destination, deux pour réduire encore plus, etc. Ces quantificateurs sont séparés par un tiret. Si Android ne trouve pas d'emplacement dont le nom corresponde exactement aux spécifications techniques du terminal, il cherchera parmi les autres répertoires qui existent la solution la plus proche. Je vais vous montrer les principaux quantificateurs (il y en a quatorze en tout, dont un bon paquet qu'on utilise rarement, j'ai donc décidé de les ignorer).

Vous n'allez pas comprendre l'attribut Priorité tout de suite, d'ailleurs il est possible que vous ne compreniez pas tout immédiatement. Lisez cette partie tranquillement, zieutez ensuite les exemples qui suivent, puis revenez à cette partie une fois que vous aurez tout compris.

Langue et région

Priorité : 2 La langue du système de l'utilisateur. On indique une langue puis, éventuellement, on peut préciser une région avec « -r ». Exemples :

  • en pour l'anglais ;
  • fr pour le français ;
  • fr-rFR pour le français mais uniquement celui utilisé en France ;
  • fr-rCA pour le français mais uniquement celui utilisé au Québec ;
  • Etc.

Taille de l'écran

Priorité : 3 Il s'agit de la taille de la diagonale de l'écran :

  • small pour les écrans de petite taille ;
  • normal pour les écrans standards ;
  • large pour les grands écrans, comme dans les tablettes tactiles ;
  • xlarge pour les très grands écrans, là on pense carrément aux téléviseurs.

Orientation de l'écran

Priorité : 5 Il existe deux valeurs :

  • port : c'est le diminutif de portrait, donc quand le terminal est en mode portrait ;
  • land : c'est le diminutif de landscape, donc quand le terminal est en mode paysage.

Résolution de l'écran

Priorité : 8

  • ldpi : environ 120 dpi ;
  • mdpi : environ 160 dpi ;
  • hdpi : environ 240 dpi ;
  • xhdpi : environ 320 dpi (disponible à partir de l'API 8 uniquement) ;
  • nodpi : pour ne pas redimensionner les images matricielles (vous savez, JPEG, PNG et GIF !).

Version d'Android

Priorité : 14 Il s'agit du niveau de l'API (v3, v5, v7 (c'est celle qu'on utilise nous !), etc.).

Regardez l'image précédente (qui de toute façon représente les répertoires créés automatiquement pour tous les projets), que se passe-t-il si l'écran du terminal de l'utilisateur a une grande résolution ? Android ira chercher dans res/drawable-hdpi ! L'écran du terminal de l'utilisateur a une petite résolution ? Il ira chercher dans res/drawable-ldpi/ ! L'écran du terminal de l'utilisateur a une très grande résolution ? Eh bien… il ira chercher dans res/drawable-hdpi puisqu'il s'agit de la solution la plus proche de la situation matérielle réelle.

Exemples et règles à suivre

  • res/drawable-small pour avoir des images spécifiquement pour les petits écrans.
  • res/drawable-large pour avoir des images spécifiquement pour les grands écrans.
  • res/layout-fr pour avoir une mise en page spécifique destinée à tous ceux qui ont un système en français.
  • res/layout-fr-rFR pour avoir une mise en page spécifique destinée à ceux qui ont choisi la langue Français (France).
  • res/values-fr-rFR-port pour des données qui s'afficheront uniquement à ceux qui ont choisi la langue Français (France) et dont le téléphone se trouve en orientation portrait.
  • res/values-port-fr-rFR n'est pas possible, c'est à ça que servent les priorités : il faut impérativement mettre les quantificateurs par ordre croissant de priorité. La priorité de la langue est 2, celle de l'orientation est 5, comme 2 < 5 on doit placer les langues avant l'orientation.
  • res/layout-fr-rFR-en n'est pas possible puisqu'on a deux quantificateurs de même priorité et qu'il faut toujours respecter l'ordre croissant des priorités. Il nous faudra créer un répertoire pour le français et un répertoire pour l'anglais.

Tous les répertoires de ressources qui sont différenciés par des quantificateurs devront avoir le même contenu : on indique à Android de quelle ressource on a besoin, sans se préoccuper dans quel répertoire aller le chercher, Android le fera très bien pour nous. Sur l'image précédente, vous voyez que l'icône se trouve dans les trois répertoires drawable/, sinon Android ne pourrait pas la trouver pour les trois types de configuration.

Mes recommandations

Voici les règles que je respecte pour la majorité de mes projets, quand je veux faire bien les choses :

  • res/drawable-hdpi ;
  • res/drawable-ldpi ;
  • res/drawable-mdpi ;
  • Pas de res/drawable ;
  • res/layout-land ;
  • res/layout.

Une mise en page pour chaque orientation et des images adaptées pour chaque résolution. Le quantificateur de l'orientation est surtout utile pour l'interface graphique. Le quantificateur de la résolution sert plutôt à ne pas avoir à ajuster une image et par conséquent à ne pas perdre de qualité.

Pour finir, sachez que les écrans de taille small et xlarge se font rares.

Ajouter un fichier avec Eclipse

Heureusement, les développeurs de l'ADT ont pensé à nous en créant un petit menu qui vous aidera à créer des répertoires de manière simple, sans avoir à retenir de syntaxe. En revanche, il vous faudra parler un peu anglais, je le crains. Faites un clic droit sur n'importe quel répertoire ou fichier de votre projet. Vous aurez un menu un peu similaire à celui représenté à l'image suivante, qui s'affichera.

L'ADT permet d'ajouter des répertoires facilement

Dans le sous-menu New, soit vous cliquez directement sur Android XML File, soit, s'il n'est pas présent, vous devrez cliquer sur Other…, puis chercher Android XML File dans le répertoire Android. Cette opération ouvrira un assistant de création de fichiers XML visible à la figure suivante.

L'assistant de création de fichiers XML

Le premier champ vous permet de sélectionner le type de ressources désiré. Vous retrouverez les noms des ressources que nous avons décrites dans le premier tableau, ainsi que d'autres qui nous intéressent moins, à l'exception de raw puisqu'il n'est pas destiné à contenir des fichiers XML. À chaque fois que vous changez de type de ressources, la seconde partie de l'écran change et vous permet de choisir plus facilement quel genre de ressources vous souhaitez créer. Par exemple pour Layout, vous pouvez choisir de créer un bouton (Button) ou un encart de texte (TextView). Vous pouvez ensuite choisir dans quel projet vous souhaitez ajouter le fichier. Le champ File vous permet quant à lui de choisir le nom du fichier à créer.

Une fois votre sélection faite, vous pouvez cliquer sur Next pour passer à l'écran suivant (voir figure suivante) qui vous permettra de choisir des quantificateurs pour votre ressource ou Finish pour que le fichier soit créé dans un répertoire sans quantificateurs.

Cette fenêtre vous permet de choisir des quantificateurs pour votre ressource

Cette section contient deux listes. Celle de gauche présente les quantificateurs à appliquer au répertoire de destination. Vous voyez qu'ils sont rangés dans l'ordre de priorité que j'ai indiqué.

Mais il y a beaucoup plus de quantificateurs et de ressources que ce que tu nous as indiqué !

Oui. Je n'écris pas une documentation officielle pour Android. Si je le faisais, j'en laisserais plus d'un confus et vous auriez un nombre impressionnant d'informations qui ne vous serviraient pas ou peu. Je m'attelle à vous apprendre à faire de jolies applications optimisées et fonctionnelles, pas à faire de vous des encyclopédies vivantes d'Android. ;)

Le champ suivant, Folder, est le répertoire de destination. Quand vous sélectionnez des quantificateurs, vous pouvez avoir un aperçu en temps réel de ce répertoire. Si vous avez commis une erreur dans les quantificateurs, par exemple choisi une langue qui n’existe pas, le quantificateur ne s'ajoutera pas dans le champ du répertoire. Si ce champ ne vous semble pas correct vis-à-vis des quantificateurs sélectionnés, c'est que vous avez fait une faute d'orthographe. Si vous écrivez directement un répertoire dans Folder, les quantificateurs indiqués s'ajouteront dans la liste correspondante.

À mon humble avis, la meilleure pratique est d'écrire le répertoire de destination dans Folder et de regarder si les quantificateurs choisis s'ajoutent bien dans la liste. Mais personne ne vous en voudra d'utiliser l'outil prévu pour. :p

Cet outil peut gérer les erreurs et conflits. Si vous indiquez comme nom « strings » et comme ressource une donnée (« values »), vous verrez un petit avertissement qui s'affichera en haut de la fenêtre, puisque ce fichier existe déjà (il est créé par défaut).

Petit exercice

Vérifions que vous avez bien compris : essayez, sans passer par les outils d'automatisation, d'ajouter une mise en page destinée à la version 8, quand l'utilisateur penche son téléphone en mode portrait alors qu'il utilise le français des Belges (fr-rBE) et que son terminal a une résolution moyenne.

Le Folder doit contenir exactement /res/layout-fr-rBE-port-mdpi-v8.

Il vous suffit de cliquer sur Finish si aucun message d'erreur ne s'affiche.

Récupérer une ressource

La classe R

On peut accéder à cette classe qui se trouve dans le répertoire gen/ (comme generated, c'est-à-dire que tout ce qui se trouvera dans ce répertoire sera généré automatiquement), comme indiqué à la figure suivante.

On retrouve le fichier R.java dans gen/<votre_package>/</votre_package>

Ouvrez donc ce fichier et regardez le contenu.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public final class R {
  public static final class attr {
  }
  public static final class dimen {
    public static final int padding_large=0x7f040002;
    public static final int padding_medium=0x7f040001;
    public static final int padding_small=0x7f040000;
  }
  public static final class drawable {
    public static final int ic_action_search=0x7f020000;
    public static final int ic_launcher=0x7f020001;
  }
  public static final class id {
    public static final int menu_settings=0x7f080000;
  }
  public static final class layout {
    public static final int activity_main=0x7f030000;
  }
  public static final class menu {
    public static final int activity_main=0x7f070000;
  }
  public static final class string {
    public static final int app_name=0x7f050000;
    public static final int hello_world=0x7f050001;
    public static final int menu_settings=0x7f050002;
    public static final int title_activity_main=0x7f050003;
  }
  public static final class style {
    public static final int AppTheme=0x7f060000;
  }
}

Ça vous rappelle quelque chose ? Comparons avec l'ensemble des ressources que comporte notre projet (voir figure suivante).

Tiens, ces noms me disent quelque chose…

On remarque en effet une certaine ressemblance, mais elle n'est pas parfaite ! Décryptons certaines lignes de ce code.

La classe layout

1
2
3
public static final class layout { 
  public static final int activity_main=0x7f030000; 
}

Il s'agit d'une classe déclarée dans une autre classe : c'est ce qui s'appelle une classe interne. La seule particularité d'une classe interne est qu'elle est déclarée dans une autre classe, mais elle peut agir comme toutes les autres classes. Cependant, pour y accéder, il faut faire référence à la classe qui la contient. Cette classe est de type public static final et de nom layout.

  • Un élément public est un élément auquel tout le monde peut accéder sans aucune restriction.
  • Le mot-clé static, dans le cas d'une classe interne, signifie que la classe n'est pas liée à une instanciation de la classe qui l'encapsule. Pour accéder à layout, on ne doit pas nécessairement créer un objet de type R. On peut y accéder par R.layout.
  • Le mot-clé final signifie que l'on ne peut pas créer de classe dérivée de layout.

Cette classe contient un unique public int, affublé des modificateurs static et final. Il s'agit par conséquent d'une constante, à laquelle n'importe quelle autre classe peut accéder sans avoir à créer d'objet de type layout ni de type R.

Cet entier est de la forme 0xZZZZZZZZ. Quand un entier commence par 0x, c'est qu'il s'agit d'un nombre hexadécimal sur 32 bits. Si vous ignorez ce dont il s'agit, ce n'est pas grave, dites-vous juste que ce type de nombre est un nombre exactement comme un autre, sauf qu'il respecte ces règles-ci :

  • Il commence par 0x.
  • Après le 0x, on trouve huit chiffres (ou moins, mais on préfère mettre des 0 pour arriver à 8 chiffres) : 0x123 est équivalent à 0x00000123, tout comme 123 est la même chose que 00000123.
  • Ces chiffres peuvent aller de 0 à… F. C'est-à-dire qu'au lieu de compter « 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 » on compte « 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F ». A, B, C, D, E et F sont des chiffres normaux, banals, même s'ils n'en n'ont pas l'air, c'est juste qu'il n'y a pas de chiffre après 9, alors il a fallu improviser avec les moyens du bord . ^^ Ainsi, après 9 on a A, après A on a B, après E on a F, et après F on a 10 ! Puis à nouveau 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B, etc.

Regardez les exemples suivants :

1
2
3
4
5
6
7
8
int deuxNorm = 2; // Valide !
int deuxHexa = 0x00000002; // Valide, et vaut la même chose que « deuxNorm »
int deuxRed = 0x2; // Valide, et vaut la même chose que « deuxNorm » et « deuxHexa » (évidemment, 00000002, c'est la même chose que 2 !)
//Ici, nous allons toujours écrire les nombres hexadécimaux avec huit chiffres, même les 0 inutiles !
int beaucoup = 0x0AFA1B00; // Valide !
int marcheraPas = 1x0AFA1B00; // Non ! Un nombre hexadécimal commence toujours par « 0x » !
int marcheraPasNonPlus = 0xG00000000; // Non ! Un chiffre hexadécimal va de 0 à F, on n'accepte pas les autres lettres !
int caVaPasLaTete = 0x124!AZ5%; // Alors là c'est carrément n'importe quoi !

Cet entier a le même nom qu'un fichier de ressources (activity_main), tout simplement parce qu'il représente ce fichier (activity_main.xml). On ne peut donc avoir qu'un seul attribut de ce nom-là dans la classe, puisque deux fichiers qui appartiennent à la même ressource se trouvent dans le même répertoire et ne peuvent par conséquent pas avoir le même nom. Cet entier est un identifiant unique pour le fichier de mise en page qui s'appelle activity_main. Si un jour on veut utiliser ou accéder à cette mise en page depuis notre code, on y fera appel à l'aide de cet identifiant.

La classe drawable

1
2
3
4
public static final class drawable { 
  public static final int ic_action_search=0x7f020000; 
  public static final int ic_launcher=0x7f020001; 
}

Contrairement au cas précédent, on a un seul entier pour plusieurs fichiers qui ont le même nom ! On a vu dans la section précédente qu'il fallait nommer de façon identique ces fichiers qui ont la même fonction, pour une même ressource, mais avec des quantificateurs différents. Eh bien, quand vous ferez appel à l'identificateur, Android saura qu'il lui faut le fichier ic_launcher et déterminera automatiquement quel est le répertoire le plus adapté à la situation du matériel parmi les répertoires des ressources drawable, puisqu'on se trouve dans la classe drawable.

La classe string

1
2
3
4
5
6
public static final class string {
  public static final int app_name=0x7f050000; 
  public static final int hello_world=0x7f050001; 
  public static final int menu_settings=0x7f050002; 
  public static final int title_activity_main=0x7f050003;
}

Cette fois, si on a quatre entiers, c'est tout simplement parce qu'on a quatre chaînes de caractères dans le fichier res/values/strings.xml, qui contient les chaînes de caractères (qui sont des données). Vous pouvez le vérifier par vous-mêmes en fouillant le fichier strings.xml.

Je ne le répéterai jamais assez, ne modifiez jamais ce fichier par vous-mêmes. Eclipse s'en occupera.

Il existe d'autres variables dont je n'ai pas discuté, mais vous avez tout compris déjà avec ce que nous venons d'étudier.

Application

Énoncé

J'ai créé un nouveau projet pour l'occasion, mais vous pouvez très bien vous amuser avec le premier projet. L'objectif ici est de récupérer la ressource de type chaîne de caractères qui s'appelle hello_world (créée automatiquement par Eclipse) afin de la mettre comme texte dans un TextView. On affichera ensuite le TextView.

On utilisera la méthode public final void setText (int id) (id étant l'identifiant de la ressource) de la classe TextView.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class Main extends Activity {
  private TextView text = null;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    text = new TextView(this);
    text.setText(R.string.hello_world);

    setContentView(text);
  }
}

Comme indiqué auparavant, on peut accéder aux identificateurs sans instancier de classe. On récupère dans la classe R l'identificateur de la ressource du nom hello_world qui se trouve dans la classe string, puisqu'il s'agit d'une chaîne de caractères, donc R.string.hello_world.

Et si je mets à la place de l'identifiant d'une chaîne de caractères un identifiant qui correspond à un autre type de ressources ?

Eh bien, les ressources sont des objets Java comme les autres. Par conséquent ils peuvent aussi posséder une méthode public String toString() ! Pour ceux qui l'auraient oublié, la méthode public String toString() est appelée sur un objet pour le transformer en chaîne de caractères, par exemple si on veut passer l'objet dans un System.out.println. Ainsi, si vous mettez une autre ressource qu'une chaîne de caractères, ce sera la valeur rendue par la méthode toString() qui sera affichée.

Essayez par vous-mêmes, vous verrez ce qui se produit. ;) Soyez curieux, c'est comme ça qu'on apprend !

Application

Énoncé

Je vous propose un autre exercice. Dans le précédent, le TextView a récupéré l'identifiant et a été chercher la chaîne de caractères associée pour l'afficher. Dans cet exercice, on va plutôt récupérer la chaîne de caractères pour la manipuler.

Instructions

  • On va récupérer le gestionnaire de ressources afin d'aller chercher la chaîne de caractères. C'est un objet de la classe Resource que possède notre activité et qui permet d'accéder aux ressources de cette activité. On peut le récupérer grâce à la méthode public Resources getResources().
  • On récupère la chaîne de caractères hello_world grâce à la méthode string getString(int id), avec id l'identifiant de la ressource.
  • Et on modifie la chaîne récupérée.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class Main extends Activity {
  private TextView text = null;
  private String hello = null;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    hello = getResources().getString(R.string.hello_world);
    // Au lieu d'afficher "Hello World!" on va afficher "Hello les Zéros !"
    hello = hello.replace("world", "les Zéros ");

    text = new TextView(this);
    text.setText(hello);

    setContentView(text);
  }
}

J'ai une erreur à la compilation ! Et un fichier similaire à mon fichier XML mais qui se finit par .out vient d'apparaître !

Ah, ça veut dire que vous avez téléchargé une version d'Eclipse avec un analyseur syntaxique XML. En fait si vous lancez la compilation alors que vous étiez en train de consulter un fichier XML, alors c'est l'analyseur qui se lancera et pas le compilateur. La solution est donc de cliquer sur n'importe quel autre fichier que vous possédez qui ne soit pas un XML, puis de relancer la compilation.


  • Au même titre que le langage Java est utile pour développer vos application, le langage XML l'est tout autant puisqu'il a été choisi pour mettre en place les différentes ressources de vos projets.
  • Il existe 5 types de ressources que vous utiliserez majoritairement :
    • drawable qui contient toutes les images matricielles et les fichiers XML décrivant des dessins simples.
    • layout qui contient toutes les interfaces que vous attacherez à vos activités pour mettre en place les différentes vues.
    • menu qui contient toutes les déclarations d'éléments pour confectionner des menus.
    • raw qui contient toutes les autres ressources au format brut.
    • values qui contient des valeurs pour un large choix comme les chaînes de caractères, les dimensions, les couleurs, etc.
  • Les quantificateurs sont utilisés pour cibler précisément un certain nombre de priorités ; à savoir la langue et la région, la taille de l'écran, l'orientation de l'écran, la résolution de l'écran et la version d'Android.
  • Chaque ressource présente dans le dossier res de votre projet génère un identifiant unique dans le fichier R.java pour permettre de les récupérer dans la partie Java de votre application.