Home
Android par la pratique
Un premier projet
Eclispe
Un premier projet

Il existe plusieurs environnements de développement pour faciliter l'écriture de code pour la plateforme Android. Pour cette présentation, les exemples traités ont été développés en utilisant Android Studio qui est l'IDE officiel pour Android :
https://developer.android.com/studio/index.html

L'organisation des sites Web étant en constante évolution si ce lien ne fonctionne pas, une simple recherche sur Google avec les mots clé Android Studio devrait permettre d'obtenir la page désirée:
http://www.google.fr/?#q=Android+Studio

Du fait des divers problèmes induits par la présence d'un proxy sur l'université et de la constante évolution de cet IDE, nous travaillerons en TP sous une même version d'Android Studio via un conteneur Docker. Pour cela, il vous faudra tout d'abord construire l'image finale de ce conteneur afin qu'un certain nombre de variables d'environnement soient automatiquement configurées en fonction de vos identifiants. Vous devrez donc exécuter à partir d'un terminal :

u1-001-1:~$ sudo dock buildstudio 'votre_mot_de_passe' studio

La commande dock vous permet d'accéder à un ensemble restreint des fonctionnalités de docker. Une fois l'image finale construite, pour lancer l'environnement Android Studio, saisissez les commandes suivantes :

u1-001-1:~$ sudo dock launchstudio
u1-001-1:~$ cd android-studio/bin
u1-001-1:~$ ./studio.sh
L'ensemble des projets que vous développerez sera sauvegardé dans le répertoire AndroidStudioProjects du conteneur. Ce répertoire est partagé avec le répertoire /scratch/studio-votre_login qui se trouve sur votre machine de travail. Ainsi lorsque le conteneur n'est plus actif, vous pourrez toujours retrouver vos projets dans cette arborescence.
Création d'un nouveau projet

Sélectionnez le menu File -> New -> Android Application Project. Inspirez-vous de la capture d'écran ci-dessous pour remplir les champs de saisie.

  • Application Name: il s'agit du nom qui s'affichera sur votre téléphone pour votre application.
  • Project Name: le nom de votre projet sous Android Studio.
  • Package Name: il s'agit d'un espace de nommage (sous forme d'arborescence) permettant de représenter de façon unique votre application parmi toutes les applications installées sur votre système.
  • Minimum Required SDK: la version minimale de l'API Android sur laquelle votre application peut s'exécuter. Votre application sur le Play Store sera invisible pour tous les systèmes ayant un numéro de version d'API inférieur.
  • Target SDK: le numéro de version de l'API Android pour lequel votre application a été développée. Cette information est utilisée par votre périphérique au moment de l'exécution de votre application. Si votre système fonctionne sous une version de l'API Android supérieure à celle spécifiée dans la paramètre Target SDK, il assurera la compatibilité afin que votre application s'exécute comme vous le souhaitez (notamment au niveau de l'apparence par défaut de la fenêtre, des menus, etc ...)
  • Compile With: indique la version de l'API avec laquelle votre projet va être compilée. Android Studio renverra un message d'erreur si lors du développement de votre projet, vous utilisez des classes ou des méthodes d'une API supérieure. Par défaut, la version proposée est la dernière fournie avec le SDK. Si vous souhaitez compiler votre application avec une autre version, il faudra télécharger l'API souhaitée à partir du menu Android SDK Manager.
Choisir la bonne API est important si vous souhaitez que votre application soit disponible pour un maximum de périphériques. Vous pouvez consulter le lien suivant pour avoir une idée de la répartition des différentes versions d'Android :

http://developer.android.com/about/dashboards/index.html

Une fois ceci configuré, cliquez sur Next, ne changez rien dans la fenêtre suivante, les options cochées par défaut permettent la création d'une arborescence pour votre projet dans votre espace de travail et la création de la classe principale représentant votre activité.

La fenêtre suivante vous permet de personnaliser l'icone de lancement de votre application. Vous pouvez par exemple choisir l'un des cliparts fourni par défaut en cliquant sur le bouton Clipart, puis Choose.

La fenêtre suivante permet de sélectionner un modèle par défaut pour l'aspect visuel de votre application. Choisissez Blank Activity.

Dans la fenêtre suivante vous pouvez changer le nom par défaut de la classe Java associée à votre application, ainsi que le nom du fichier de ressources XML contenant la description de l'aspect visuel de votre application (ce fichier est détaillé dans la partie intitulée Layout).

Une fois vos choix validés, vous devez normalement voir apparaître une vue de l'aspect visuel de votre application, ainsi que l'arborescence de votre projet sur la gauche de la fenêtre principale d'Android Studio.

Exécution de votre application

à faire.

Une première modification : le fichier strings.xml

Votre application affiche la chaîne Hello World !. Cette chaîne est stockée dans l'arborescence de vore projet dans le fichier strings.xml situé dans le répertoire res.

Ce fichier au format XML permet de stocker les chaînes de caractère utilisées dans votre application (texte à afficher, texte de bouton, menus ...). Quand vous cliquez sur ce ficher dans l'arborescence de votre projet, Android Studio vous propose par défaut une interface simplifiée pour effectuer des modifications. Nous allons travailler directement sur le source XML. Pour cela, cliquer sur l'onglet strings.xml de l'interface simplifiée.
Dans le code source qui s'affiche, vous pourrez remarquer :
  • une balise contenant le nom de votre application,
  • une balise contenant la chaîne Hello world!
  • une balise contenant le texte s'affichant lorsque vous cliquez sur le bouton menude votre téléphone. Selon votre modèle de téléphone, ce bouton peut avoir diverses apparences
Remplacez la chaîne Hello world!, par Bonjour le monde ! et relancez l'exécution de votre application pour constater le changement. Dans la section Layout, nous verrons comment utiliser les éléments définis dans ce fichier au moment du rendu visuel de l'application.

            

Le fichier AndroidManifest.xml

Ce fichier situé à la racine de l'arborescence de votre projet contient un certain nombre d'informations indispensables à l'élaboration de votre application. Notez que certaines de ces informations correspondent à celles que vous avez fournies lors de la création de votre projet. Vous y trouverez en particulier:

  • android:versionCode : un entier représentant le numéro de version de votre application.
  • android:versionName : une chaîne de caractères représentant la version de votre application sous la forme majeur.mineur. Cette chaîne est consultable par un utilisateur de votre application.
  • android:minSdkVersion, android:targetSdkVersion : le numéro d'API minimum et d'API cible pour votre application.
  • android:icon : le fichier contenant l'icone de lancement de votre application. Notez que cette icone au format png doit se trouver dans les répertoires drawable-*, chacun de ces répertoires permettant de placer un fichier image correspondant à la résolution de l'écran
  • android:label: le nom de votre application sous la forme d'une référence au champ app_name se trouvant dans le fichier strings.xml.
  • android:name: le nom de la classe Java principale associée à votre application. Il doit être de la forme package.nom. En spécifiant uniquement .nom le nom du package est déduit de la variable package définie dans les premières lignes du fichier AndroidManifest.
C'est aussi dans ce fichier que vous pourrez:
  • autoriser votre application à lancer une autre application,
  • autoriser votre application à accéder à Internet,
  • autoriser votre application à sauvegarder et/ou lire des données sur la carte SD,
  • ...
Pour plus d'informations, cf. http://developer.android.com/guide/topics/manifest/manifest-intro.html

            

Le fichier activity_hello.xml

Dans le répertoire res/layout de votre projet se trouve le fichier activity_hello.xml. Ce dernier contient la description visuelle de votre application (emplacement des boutons, des zones de texte, ...). L'aspect visuel d'une application se fait en utilisant un Layout. Il en existe de plusieurs types. Nous n'aborderons ici que les LinearLayout et les RelativeLayout. Pour une description plus complète, cf :

http://developer.android.com/guide/topics/ui/declaring-layout.html.

Dans un LinearLayout de type vertical, tous les composants de votre application sont positionnés les uns en dessous des autres, selon l'ordre de leur déclaration dans le fichier xml. Dans un LinearLayout de type horizontal, tous les composants de votre application sont positionnés les uns à côté des autres.

Pour la suite nous nous intéresserons aux RelativeLayout qui autorisent plus de souplesse dans le positionnement des éléments, notamment en permettant de placer un élément en fonction de la position d'un autre (au-dessus, en-dessous, à côté, aligné avec le bord gauche d'un certain élément, etc ...). Examinons le contenu du fichier activity_hello.xml


            Les lignes 3-4 permettent de définir la largeur et la hauteur du Layout. Le mot clé
            match_parent signifie que notre Layout occupera toute la largeur et la hauteur de son élément
            parent, en l'occurence ici l'écran de votre téléphone.
            
Les lignes 5-8 définissent des marges pour la zone d'affichage en faisant référence à des dimensions stockées dans le fichier res/values/dimens.xml.

            
Les lignes 11-14 contiennent la définition d'une zone d'affichage de texte (TextView). On y trouve la largeur et la hauteur de cette zone. Le mot clé wrap_content signifie que la hauteur et la dimension s'adapteront automatiquement au contenu de la zone. Finalement le texte à afficher est précisé en faisant référence à l'entrée hello_world du fichier strings.xml que nous avons présenté dans la partie intitulée Première application.

Modification du fichier activity_hello.xml

L'objectif de cette partie est de modifier notre application afin d'obtenir une interface permettant à l'utilisateur de saisir son nom et son prénom. On rajoutera de plus un bouton de validation qui lorsque l'on cliquera dessus affichera dans une zone de texte la chaîne : Bonjour prénom nom. L'aspect final de notre application sera donc le suivant :

Ajout de zones de saisie de texte

Les zones de saisie de texte se déclarent à l'aide de la balise <EditText>. Remplaçons les lignes 11-14 du fichier activity_hello.xml par :


                

L'attribut android:id permet d'associer un identificateur à la zone. Cela sera indispensable pour pouvoir par la suite interagir avec le code Java de notre application. De plus, cela permet de positionner les éléments les uns par rapport aux autres dans le layout. Cet attribut peut prendre deux formes :

  • @+id/... : c'est la première fois que l'identifiant est déclaré
  • @id/... : l'attribut a déja été déclaré précédemment dans le fichier (un exemple de cette situation va être traité par la suite).
Cette déclaration nous permet simplement d'obtenir une zone de saisie de texte sans aucune information supplémentaire
Rajoutons une zone de type TextView afin d'afficher la chaîne Nom : à gauche de notre zone de saisie. Ceci nous permet d'illustrer que dans un RelativeLayout, l'ordre de déclaration des différents éléments visuels de l'application ne correspond pas forcément à leur ordre d'apparition à l'écran. Dans un RelativeLayout, on peut spécifier la position d'un élément par rapport à un autre. Par défaut, le premier élément déclaré dans le fichier se trouvera en haut à gauche de l'écran, sinon ce sera l'élément dont la description ne contienr aucune information quant à son positionnement relatif. Le code du fichier activity_hello.xml est alors le suivant :

                Plusieurs choses à remarquer :
                
  • Ligne 6 : nous indiquons que la zone de saisie de texte doit se situer à droite de la zone d'affichage en spécifiant l'identifiant de cette dernière. Comme la zone d'affichage n'a pas encore été définie, nous créons cet identifiant @+id.
  • Ligne 10 : nous attribuons un identifiant à la zone d'affichage de texte. Ce dernier ayant été défini précédemment nous utilisons l'attribut @id.
  • Ligne 13 : nous indiquons que le texte à afficher correspond à l'entrée s_nom du fichier de ressources strings.xml

                
Exercice : Réécrivez le fichier actvity_hello.xml en déclarant tout d'abord la zone d'affichage de texte puis la zone de saisie de texte.
Solution

                        

Exercice : Rajoutez à droite de la zone de saisie du nom, une zone d'affichage de texte et une zone de saisie de texte permettant à l'utilisateur de rentrer son prénom.
Solution

                        

Si vous exécutez votre application, vous constaterez deux problèmes esthétiques :
  
  • Le texte saisi n'est pas aligné avec les chaînes Nom et Prénom. Pour modifier ceci, il suffit d'utiliser la propriété android:layout_alignBaseline permettant d'aligner la ligne de base de l'élément courant avec l'élément dont on spécifie l'identifiant.
  • La chaîne Prénom se déplace au fur et à mesure que l'on saisit des caractères dans la zone de saisie dédié au Nom. Pour éviter ceci, on peut attribuer par exemple une certaine largeur aux zones de saisie de texte (au lieu d'utiliser la constante prédéfinie wrap_content).

                

Ajout d'un bouton
Nous souhaitons maintenant ajouter un bouton qui lorsque l'on cliquera dessus affichera le message Bonjour prénom nom. Le bouton devra être centré et aligné en bas de l'écran. Nous utiliserons pour cela l'élément Button et les propriétés android:layout_centerInParent et android:layout_alignParentBottom. Le texte à afficher sur le bouton doit faire référence à une des entrées du fichier strings.xml.
Remarque : Il faut aussi ajouter une zone d'affichage de texte afin d'afficher le résultat final sous les zones de saisie. Une marge haute a été ajouté à élément afin qu'il y ait suffisamment d'espace entre les zones de saisie et la zone de résultat.

                Pour plus de renseignements sur les différentes propriétés permettant de gérer les alignements,
                cf. http://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html
            

Dans cette partie, nous allons voir comment interagir en Java avec les éléments qui composent la partie visuelle de notre application.

Le fichier R.java

Lors de la compilation de votre projet, Android Studio crée automatiquement dans le dossier gen de votre projet un fichier R.java contenant en particulier l'ensemble des identifiants que vous avez défini dans le fichier activity_hello.xml. On les retrouve dans la classe statique id définie dans ce fichier.


        
Le fichier HelloActivity.java

Ce fichier est situé dans le répertoire src de votre dossier. Il contient la définition de la classe principale représentant votre application. Dans cette classe, les instructions contenues dans la méthode onCreate seront automatiquement exécutées lors du lancement de votre application. Cette méthode contient deux instructions :

  • super.onCreate(savedInstanceState) : qui exécute les instructions de la méthode onCreate de la classe mère ActionBarActivity. L'objet passé en paramè sera détaillé dans la partie Cycle de vie.
  • setContentView(R.layout.activity_hello) : qui se charge du rendu visuel de l'application à partir des données du fichier activity_hello.xml.

            

La méthode findViewById

Afin d'interagir avec les composants définis dans le fichier activity_hello.xml, il faut définir au niveau du fichier HelloActivity.java des objets de même type. Ainsi pour notre application, nous allons définir deux objets de type EditText, un objet de type TextView et un objet de type Button (lignes 13-15). Notons que la déclaration de ces objets nécessite d'importer des modules supplémentaires (lignes 7-9). Ces derniers sont proposés automatiquement par Eclipe au moment de la déclaration des objets. Le lien entre ces objets avec les composants définis dans le fichier activity_hello.xml se fait via la méthode findViewById(identifiant) qui prend en paramètre l'un des identifiants de la classe statique id du fichier R.java et qui renvoie un objet général de type View qu'il faudra transtyper en l'objet voulu (lignes 22-25).


            

Mise en place d'un gestionnaire d'évènement

Il faut à présent détecter le click de l'utilisateur sur le bouton de notre interface afin d'afficher le message Bonjour prénom nom. D'après la documentation de l'API Android, l'objet Button est dérivé de l'objet View dont la méthode setOnClickListener permet de déclencher une action à exécuter lorsque l'on clique sur l'objet (ligne 7). Cette méthode prend en paramètre une interface de type View.OnClickListener qui contient la définition de la méthode onClick qui sera exécutée lors du click de l'utilisateur. On peut passer en paramètre de la méthode setOnClickListener, une référence à notre classe principale (this) auquel cas il faudra d'une part spécifier qu'elle implémente l'interface OnClickListener (ligne 1) et d'autre part ajouter la définition de la méthode onClick (lignes 21-25). Ces deux dernières actions sont normalement automatiquement proposées par Android Studio dès lors que vous utilisez l'instruction setOnClickListener.


            

Terminons l'application

Il suffit à présent de compléter la méthode onClick. Pour cela, il faut:

  • Récupérer les informations saisies par l'utilisateur dans les deux zones de saisie de texte.
  • Construire la chaîne Bonjour prénom nom.
  • Afficher cette chaîne dans la zone résultat.
La documentation de la classe EditTex ( http://developer.android.com/reference/android/widget/EditText.html) contient la définition de la méthode getText() qui renvoie un objet de type Editable contenant la chaîne saisie par l'utilisateur dans la zone de saisie. La méthode toString() appliquée à un objet de type Editable permet d'extraire cette chaîne.
La documentation de la classe TextView ( http://developer.android.com/reference/android/widget/TextView.html) contient la définition de la méthode setText() qui permet en particulier de placer une chaîne de caractères dans un objet de type View.

            

L'attribut XML onClick pour les objets de type View

Pour les objets de type View (comme les boutons), déclarer un gestionnaire d'évènement pour le click peut être réalisé de façon plus simple à partir de la balise associée à la vue définie dans le fichier de description XML du layout. En effet, la propriété android:onClick des objets de type View permet de spécifier le nom d'une méthode à exécuter lors du click sur l'objet. Cette méthode doit être publique et déclarée dans la classe principale de votre activité. Elle doit accepter en paramètre un objet de type View qui sera remplacé lors de l'appel par l'objet sur lequel le click aura eu lieu. Ainsi, il n'est plus nécessaire dans le fichier HelloActivty.java de placer un gestionnaire d'évènement et d'implémenter l'interface View.OnClickListener. De ce fait, il n'est plus nécessaire de déclarer un objet de type Button. Dans le fichier activity_hello.xml, on modifie la définition de l'élément Button comme suit:


                et le fichier HelloActivity.java devient
                

            

Ecriture dans les logs

Il peut être utile lors de l'exécution d'une application d'observer la valeur prise par certaines variables. Pour cela, on peut utiliser la fenêtre des messages (Logcat) disponible sous Android Studio. Pour afficher un message dans cette fenêtre, il faut utiliser les méthodes Log.v(), Log.d(), Log.i(), Log.w(), ou Log.e(). Chacune de ces méthodes est associée à un niveau afin de classifier l'affichage des messages : verbose, debug, information, warning, error. Ces méthodes prennent en entrée deux paramètres : une chaîne de caractères qui est une étiquette et une chaîne de caractères qui correspond au message à afficher. Voici par exemple, comment afficher dans la fenêtre Logcat le texte du bouton sur lequel on clique dans l'activité HelloActivity.java.


            

Les différents états d'une application

Lors de son exécution, une application passe par différents états selon les actions effectuées soit par l'utilisateur (lancement d'une autre aplication, rotation de l'écran), soit par le système (affichage d'une notification type sms, réception d'un appel, gestion de la mémoire). Le système Android utilise un mécanisme de pile pour gêrer les applications. Lorsqu'une application s'exécute, elle est placée au sommet de la pile et l'utilisateur peut interagir avec cette dernière. L'application qui avait précédemment le focus, le perd et continue son exécution en arrière plan, elle reste donc active en mémoire. Si jamais la pile est pleine au moment du lancement d'une nouvelle application, l'application située en bas de pile est détruite par le système et son emplacement mémoire est libéré.

Dans le cycle de vie d'une application, on peut distinguer essentiellement trois états:

  • L'application est active, l'utilisateur interagit avec cette dernière.
  • L'application a perdu le focus mais est toujours visible à l'écran, elle est en pause. C'est le cas par exemple lorsq'un message d'alerte vient s'afficher par dessus votre application. Dans cet état, le système peut décider si cela est nécessaire de détruire l'application.
  • L'application n'est plus visible, mais elle est toujours résidente en mémoire, elle est stoppée. Dans cette situation, le système peut à nouveau décider de détruire l'application pour libérer de la mémoire.
Le diagramme ci-dessous disponible sur le site officiel developer.andoid.com illustre le cyle de vie d'une application en spécifiant les différentes méthodes qui sont exécutées selon le contexte.

Lors du développement d'une application, il est important de prendre en compte que:

  • La vie complète d'une activité se déroule entre le premier appel à la méthode onCreate et l'appel de la méthode onDestroy.
  • L'intervalle durant lequel l'application est visible est délimité par l'appel des méthodes onStart et onStop. Attention, l'application est visible, ce qui ne signifie pas forcément que l'utilisateur peut interagir avec cette dernière.
  • L'intervalle durant lequel l'utilisateur peut interagir avec l'application correspond à l'appel des méthodes onResume et onPause.

onCreate(Bundle state)

Cette méthode est exécutée lors du premier lancement de l'application. Elle prend en paramètre un objet de type Bundle qui correspond à une sorte de dictionnaire permettant d'associer à une clé (une chaîne de caractères), un objet (booléen, entier, réel, chaîne de caractères, tableau, classe sérialisable,...). Ainsi avant qu'une application soit détruite, il est possible de sauvegarder certains objets et de les récupérer via ce Bundle lorsque l'application est relancée (cf. paragraphe Sauvegarde et restauration des données).

onStart()

Cette méthode est exécutée à chaque fois que l'utilisateur lance une application non visible, qu'elle fasse partie ou non de la pile des applications en cours. L'application devient alors visible.

onRestart()

Exécutée à chaque fois que l'utilisateur relance une application non visible qui faisait partie de la pile des applications en cours (i.e. résidente en mémoire). Dans ce cas, cette méthode est exécutée avant la méthode onStart.

onResume()

Exécutée (après onStart) lorsque :

  • L'application est lancée pour la première fois.
  • L'application (invisible) est relancée et fait partie de la pile des applications en cours
Exécutée (après onPause) lorsque l'application est visible en arrière plan et qu'elle reprend le focus.

onPause()

Exécutée lorsque l'application perd le focus et ne se trouve donc plus au premier plan, soit suite à une action du système (réception d'un message par exemple), soit suite à une action de l'utilisateur (passage à une autre application). C'est dans cette méthode qu'il faudra penser à "désactiver" toutes les ressources utiles uniquement lorsque l'application est visible et qui sont consommatrices de CPU, ou de batterie.

onStop()

Exécutée lorsque l'application n'est plus visible, soit parce qu'elle va être détruite, soit parce qu'elle va passer en arrière plan dans la pile des applications en cours.

onDestroy()

Exécutée lorsque l'application va être détruite. On pensera à ce stade à libérer toutes les ressources allouées par l'application (les connexions réseaux ouvertes par exemple).

Redéfinition des méthodes impliquées dans le cyle de vie d'une application

Toutes les méthodes décrites précédemment sont définies dans la superclasse dont hérite la classe principale associée à votre application (ActionBarActivity par exemple). Vous pouvez les redéfinir dans votre classe principale pour satisfaire vos propres contraintes sans oublier de faire appel en premier lieu au super constructeur associé. L'exemple ci-dessous se contente d'afficher dans la fenêtre des logs de l'environnement Android Studio, par quel état passe votre application. Faites différents tests en lançant votre application, puis pivotez votre téléphone, passez à une autre application via la touche Home de votre téléphone, relancez l'application via un appui long sur la touche Home pour obtenir la liste des dernières applications lancées, quittez l'application via la touche Retour,...


            

Plus de renseignements sur le cycle de vie d'une application peuvent être trouvées ici:
http://developer.android.com/guide/components/activities.html#Lifecycle
http://developer.android.com/reference/android/app/Activity.html

Sauvegarde et restauration des données

D'après le diagramme du cycle de vie d'une application, il apparaît qu'après l'appel de la méthode onPause() ou onStop(), le système peut décider de détruire l'application. La méthode onPause() étant la première à être exécutée, c'est donc dans cette dernière qu'il faut placer des instructions de sauvegarde de certaines données que l'on souhaiterait pouvoir retrouver si l'application est détruite par le système et relancée par l'utilisateur. Nous allons traiter ceci à travers un exemple.

Exercice : Définissez un nouveau Projet nommé CycleActivity et créez un layout permettant d'obtenir le rendu visuel suivant (il faudra prévoir une zone d'affichage de texte sous le bouton Show).
Solution

                    

Exercice : Complétez le fichier CycleActivity.java de façon à ce que:
  • Lorsque l'on clique sur le bouton Save, le texte saisi par l'utilisateur dans la zone pourvue à cet effet, soit sauvegardé dans la variable globale texte.
  • Lorsque l'on clique sur le bouton Show, le contenu de la variable texte soit affiché dans la zone de texte déclarée après le bouton Show.
Solution

                    

Exécutez votre application comme suit :

  • Entrez un texte, cliquez sur Save, puis sur Show.
  • Entrez un nouveau texte, cliquez sur Save. Pivotez votre téléphone pour le mettre en mode paysage, puis cliquez sur Show. Que constatez-vous ?
Le contenu de la variable globale texte a été perdu. En utilisant les messages de log pour faire afficher les différentes étapes du cycle de vie de votre application, vous pouvez observer que lors du pivotement de l'écran, votre application est détruite par le système (appel à onDestroy()). En effet lors de la rotation de l'écran, il se peut que l'application doive appliquer un nouveau layout plus adapté à l'orientation de ce dernier. Or c'est l'instruction setContentView(R.layout....) de la méthode onCreate() qui se charge de cette tâche. La méthode onCreate() n'étant exécutée qu'au lancement de l'application, il est donc nécessaire de relancer celle-ci.
Exercice : Modifiez votre application de façon à ce que la méthode show affiche aussi le texte saisi par l'utilisateur en utilisant directement la méthode getText() et non pas en utilisant la variable texte. Exécutez votre application, saisissez une valeur, cliquez sur Save, puis sur Show, faites pivoter votre écran et cliquez à nouveau sur Show/ Que constatez-vous~?
Solution

                    

Le contenu de la zone de texte a été sauvegardé et il s'affiche après la rotation de l'écran. Pour chaque objet de type View, Android sauvegarde automatiquement certaines informations (tel que le texte saisi par l'utilisateur dans une zone d'édition) dans un objet de type Bundle. Il s'agit d'une sorte de dictionnaire permettant d'associer un objet (chaine de caractères, tableau d'entiers, tout objet sérialisable, ...) à une clé (une chaine de caractères). Lorsque la méthode onCreate() s'exécute elle recçoit en paramètre cet objet et c'est l'appel du superconstructeur de onCreate() qui se charge de rétablir les informations sauvés.

Important Pour que ceci fonctionne, il est indispensable que chaque objet de type View défini dans le layout possède un identifiant via l'attribut android:id.

Si pour les besoins de votre application, vous devez sauvegarder des données autres que celles attachées à des vues, vous allez devoir redéfinir la méthode onSaveInstanceState(). Cette dernière est automatiquement appelée par la méthode onPause() et prend en paramètre un objet de type Bundle que l'on peut utiliser pour sauvegarder des informations. Ainsi pour conserver la valeur de la variable texte, il suffit d'utiliser la méthode putString(clé,valeur) de la classe Bundle pour associer à la clé clé, la valeur sauvegardée.

            Lorsque la méthode onCreate s'exécute, il suffit de vérifier si l'objet de type Bundle reçu en paramètre
            n'est pas vide, auquel cas on pourra récupérer la ou les valeurs sauvegardées.
            

            Une autre façon de procéder consiste à redéfinir la méthode onRestoreInstanceState(Bundle B) qui est
            exécutée par la méthode onStart() uniquement si le paramètre B n'est pas vide. Il est alors inutile de faire
            ce test dans la méthode onCreate().
            

            ATTENTION ! Dans ce cas, il est important de ne pas oublier de faire appel au super constructeur de la méthode
            onRestoreInstanceState qui se charge de sauvegarder automatiquement les informations liées aux objets de type View.
            

Remarque importante : cette sauvegarde des données ne fonctionne que dans le cas où c'est le système qui décide de détruire l'application pour la relancer immédiatement (cas de la rotation de l'écran). Si l'utilisateur quitte volontairement l'application (exécution de la méthode onDestroy), ou si le système supprime l'application sans la relancer, les données placées dans le Bundle sont perdues. Afin de conserver et restaurer des données entre deux exécutions d'une application, on peut alors par exemple utiliser le ménisme des Shared Preferences ou une base de données.

Le mécanisme des Shared Preferences permet de sauvegarder des informations sous la forme clé/valeur. La clé est une chaîne de caractères et la valeur peut être de type boolean, float, int, long, ou string. Il s'agit d'une sauvegarde permanente, les données sont stockées sur le téléphone dans fichier liée à l'application. Lors de la désinstallation de l'application, les données seront supprimées.
Création et accès au fichier des préférences

Pour lier un fichier de préférences à votre application (ou utiliser un fichier précédemment lié), il faut utiliser la méthode

SharedPreferences getPreferences (int mode).
Le paramètre mode permet de spécifier si les préférences sont accessibles uniquement par l'application (mode = MODE_PRIVATE) ou si elles sont accessibles par n'importe quelle autre application (mode = MODE_WORLD_READABLE). Il est aussi possible de spécifier si le fichier des préférences peut être modifié par d'autres applications (mode = MODE_WORLD_WRITEABLE).
SharedPreferences sp = getPreferences (MODE_PRIVATE).
Si vous souhaitez gêrer plusieurs fichiers de préférence pour votre application, il faut dans ce cas utiliser la méthode
SharedPreferences getSharedPreferences (String name, int mode).
qui permet de préciser le nom du fichier des préférences.

Ecriture dans le fichier des préférences

L'écriture dans le fichier se fait via un objet de type Sharedpreferences.Editor() que l'on obtient en appliquant la méthode edit() à l'objet de type SharedPreferences obtenu précédemment. Selon la valeur que l'on souhaite sauvegarder, on utilisera l'une des variantes de la méthode put (par exemple putInt) afin de placer un couple clé/valeur dans le fichier des préférences. Il faut ensuite appeler la méthode apply() ou commit() pour que cette insertion soit prise en compte. Avec la méthode apply() le couple clé/valeur est sauvegardé en mémoire et effectue de façon asynchrone l'écriture dans le fichier. La méthode commit() effectue une écriture synchrone dans le fichier.

SharedPreferences.Editor spe = sp.edit();
spe.putInt("MA_CLE",classement);
spe.commit()
Lecture dans le fichier des préférences

La lecture d'un couple clé/valeur se fait à partir de l'objet de type SharedPreferences obtenu précédemment. Selon la valeur que l'on souhaite récupérer, on utilisera l'une des variantes de la méthode get (par exemple getInt). Dans le cas de la méthode getInt, on pourra donner une valeur par défaut si la clé recherchée n'existe pas.

classement = sp.getInt("MA_CLE", valeur_par_defaut);
La méthode getAll() permet de récupérer l'ensemble des couples clés/valeurs stockés dans le fichier des préférences/ Elle renvoie un objet de type Map.
Map<String,?> dico = sp.getAll();
/* on parcourt les clés */
for (String cle : dico.keySet())
{
 /* Pour chaque clé la valeur correspondante */
 /* est obtenue via dico.get(cle) */
}
Dans cette partie, nous allons apprendre comment :
La classe Intent

http://developer.android.com/training/basics/firstapp/starting-activity.html
http://developer.android.com/guide/components/intents-filters.html

Lorsqu'une application est composée de plusieurs activités, il est parfois nécessaire de pouvoir déclarer une unique instance d'un (ou plusieurs) objet(s) utilisable(s) par la suite dans les différentes activités. Ce peut être le cas lorsque l'on initialise une connexion réseau devant être utilisée par la suite par différentes activités ou bien lorque l'on travaille avec une base de données devant être consultée et/ou modifiée par les activités composant votre application.

Pour répondre à cette problématique on pourra créé une classe dite "singleton" dont les caractéristiques sont les suivantes :


        

Une fois cette classe déclarée, voici comment l'utiliser afin d'obtenir (et partager) une instance unique d'un objet particulier :


    
Généralités sur les BD : http://developer.android.com/training/basics/data-storage/databases.html
TP : http://veron.univ-tln.fr/ANDROID/TP/tpbd.pdf
Le problème ANR : http://developer.android.com/training/articles/perf-anr.html

AsyncTask : http://developer.android.com/reference/android/os/AsyncTask.html