Vous êtes sur la page 1sur 147

Programmation mobile avec Android

Pierre Nerzic - pierre.nerzic@univ-rennes1.fr

fvrier-mars 2016

Abstract

Il sagit des transparents du cours mis sous une forme plus facilement imprimable et lisible.
Ces documents ne sont pas totalement libres de droits. Ce sont des supports de cours
mis votre disposition pour vos tudes sous la licence Creative Commons Attribution - Pas
dUtilisation Commerciale - Partage dans les Mmes Conditions 4.0 International.

Version du 07/03/2017 08:57

Table des matires

1 Environnement de dveloppement 14
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.1.1 Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.1.2 Dfinition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.1.3 Composants dAndroid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.1.4 Programmation dapplications . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2 SDK Android et Android Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2.1 SDK et Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2.2 SDK Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2.3 Choix des lments du SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2.4 Dossiers du SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.2.5 Android Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.3 Premire application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.1 Objectif de la semaine 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.2 Assistant de cration dapplication . . . . . . . . . . . . . . . . . . . . . . . . 18

1
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

1.3.3 Choix de la version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18


1.3.4 Choix de la version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.5 Choix du type dapplication . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.6 Points configurer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.7 Noms des packages et classes . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.3.8 Rsultat de lassistant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.3.9 Fentre du projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.3.10 diteurs spcifiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.3.11 Exemple res/values/strings.xml . . . . . . . . . . . . . . . . . . . . . . . 23
1.3.12 Exemple res/layout/main.xml . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.3.13 Source XML sous-jacent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.3.14 Reconstruction du projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.3.15 Gradle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.3.16 Gradle en ligne de commande . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.4 Premire excution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.4.1 Excution de lapplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.4.2 Assistant de cration dune tablette virtuelle . . . . . . . . . . . . . . . . . . 27
1.4.3 Caractristiques dun AVD . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.4.4 Lancement dune application . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.4.5 Application sur lAVD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.4.6 Contrle de lAVD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.5 Communication AVD - Android Studio . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.5.1 Fentres Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.5.2 Fentre LogCat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.5.3 Filtrage des messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.5.4 mission dun message pour LogCat . . . . . . . . . . . . . . . . . . . . . . . 29
1.5.5 Logiciel ADB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.5.6 Mode demploi de ADB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.5.7 Mode demploi, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.5.8 Systme de fichiers Android . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.5.9 Mode demploi, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.6 Cration dun paquet installable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.6.1 Paquet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.6.2 Signature dune application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

2
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

1.6.3 Cration du keystore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32


1.6.4 Cration dune cl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1.6.5 Cration du paquet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1.6.6 Et voil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

2 Cration dinterfaces utilisateur 34


2.1 Interface et ressources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.1.1 Activits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.1.2 Cration dun cran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.1.3 Identifiant de ressource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.1.4 La classe R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.1.5 Rappel sur la structure dun fichier XML . . . . . . . . . . . . . . . . . . . . 36
2.1.6 Espaces de nommage dans un fichier XML . . . . . . . . . . . . . . . . . . . 36
2.1.7 Cration dune interface par programme . . . . . . . . . . . . . . . . . . . . . 36
2.1.8 Programme et ressources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.1.9 Ressources de type chanes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.1.10 Traduction des chanes (localisation) . . . . . . . . . . . . . . . . . . . . . . . 37
2.1.11 Rfrencement des ressources texte . . . . . . . . . . . . . . . . . . . . . . . 38
2.1.12 Identifiants et vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.1.13 @id/nom ou @+id/nom ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.1.14 Images : R.drawable.nom . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.1.15 Tableau de chanes : R.array.nom . . . . . . . . . . . . . . . . . . . . . . . . 39
2.1.16 Autres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.2 Dispositions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.2.1 Structure dune interface Android . . . . . . . . . . . . . . . . . . . . . . . . 40
2.2.2 Arbre des vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.2.3 Reprsentation en XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.2.4 Paramtres de positionnement . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.2.5 Paramtres gnraux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.2.6 Autres paramtres gomtriques . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.2.7 Marges et remplissage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.2.8 Groupe de vues LinearLayout . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.2.9 Pondration des tailles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.2.10 Exemple de poids diffrents . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

3
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

2.2.11 Groupe de vues TableLayout . . . . . . . . . . . . . . . . . . . . . . . . . . 43


2.2.12 Largeur des colonnes dun TableLayout . . . . . . . . . . . . . . . . . . . . . 44
2.2.13 Groupe de vues RelativeLayout . . . . . . . . . . . . . . . . . . . . . . . . 44
2.2.14 Utilisation dun RelativeLayout . . . . . . . . . . . . . . . . . . . . . . . . 44
2.2.15 Autres groupements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.3 Composants dinterface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.3.1 Vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.3.2 TextView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.3.3 Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.3.4 Bascules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.3.5 EditText . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.3.6 Autres vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.4 Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.4.1 Styles et thmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.4.2 Dfinir un style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.4.3 Utiliser un style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.4.4 Utiliser un thme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.4.5 Cest tout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

3 Vie dune application 48


3.1 Applications et activits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.1.1 Composition dune application . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.1.2 Dclaration dune application . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.1.3 Scurit des applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.1.4 Autorisations dune application . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.1.5 Dmarrage dune application . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.1.6 Dmarrage dune activit et Intents . . . . . . . . . . . . . . . . . . . . . . 50
3.1.7 Lancement dune activit par programme . . . . . . . . . . . . . . . . . . . . 50
3.1.8 Lancement dune application Android . . . . . . . . . . . . . . . . . . . . . . 50
3.1.9 Lancement dune activit dune autre application . . . . . . . . . . . . . . . . 50
3.2 Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.2.1 Fonctionnement dune application . . . . . . . . . . . . . . . . . . . . . . . . 51
3.2.2 Navigation entre activits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.2.3 Lancement sans attente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

4
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

3.2.4 Lancement avec attente de rsultat . . . . . . . . . . . . . . . . . . . . . . . 51


3.2.5 Lancement avec attente, suite . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.2.6 Terminaison dune activit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.2.7 Mthode onActivityResult . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.2.8 Transport dinformations dans un Intent . . . . . . . . . . . . . . . . . . . . 54
3.2.9 Extraction dinformations dun Intent . . . . . . . . . . . . . . . . . . . . . 54
3.2.10 Contexte dapplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.2.11 Dfinition dun contexte dapplication . . . . . . . . . . . . . . . . . . . . . . 54
3.2.12 Dfinition dun contexte dapplication, suite . . . . . . . . . . . . . . . . . . 55
3.2.13 Dfinition dun contexte dapplication, fin . . . . . . . . . . . . . . . . . . . . 55
3.3 Activits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.3.1 Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.3.2 Cycle de vie dune activit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.3.3 vnements de changement dtat . . . . . . . . . . . . . . . . . . . . . . . . 56
3.3.4 Squelette dactivit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.3.5 Terminaison dune activit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.3.6 Pause dune activit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.3.7 Arrt dune activit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.3.8 Enregistrement de valeurs dune excution lautre . . . . . . . . . . . . . . 58
3.3.9 Restaurer ltat au lancement . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.4 Vues et activits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.4.1 Obtention des vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.4.2 Proprits des vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.4.3 Actions de lutilisateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.4.4 Dfinition dun couteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.4.5 couteur priv anonyme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.4.6 couteur priv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.4.7 Lactivit elle-mme en tant qucouteur . . . . . . . . . . . . . . . . . . . . 60
3.4.8 Distinction des metteurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.4.9 vnements des vues courantes . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.4.10 Cest fini pour aujourdhui . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

5
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

4 Application liste 62
4.1 Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.1.1 Principe gnral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.1.2 Schma global . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.1.3 Une classe pour reprsenter les items . . . . . . . . . . . . . . . . . . . . . . 63
4.1.4 Donnes initiales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.1.5 Copie dans un ArrayList . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.1.6 Le container Java ArrayList<type> . . . . . . . . . . . . . . . . . . . . . . . 64
4.1.7 Donnes initiales dans les ressources . . . . . . . . . . . . . . . . . . . . . . . 65
4.1.8 Donnes dans les ressources, suite . . . . . . . . . . . . . . . . . . . . . . . . 65
4.1.9 Remarques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.2 Affichage de la liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.2.1 Activit spcialise ou layout . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.2.2 Mise en uvre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.2.3 Layout de lactivit pour afficher une liste . . . . . . . . . . . . . . . . . . . . 66
4.2.4 Mise en place du layout dactivit . . . . . . . . . . . . . . . . . . . . . . . . 66
4.2.5 Layout pour un item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.2.6 Autre layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.2.7 Layouts prdfinis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.3 Adaptateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.3.1 Relations entre la vue et les donnes . . . . . . . . . . . . . . . . . . . . . . . 68
4.3.2 Rle dun adaptateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.3.3 Adaptateurs prdfinis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.3.4 ArrayAdapter<Type> pour les listes . . . . . . . . . . . . . . . . . . . . . . . 68
4.3.5 Exemple demploi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
4.3.6 Affichage avec une ListActivity . . . . . . . . . . . . . . . . . . . . . . . . 69
4.3.7 Exemple avec les layouts standards . . . . . . . . . . . . . . . . . . . . . . . 69
4.4 Adaptateur personnalis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.4.1 Classe Adapter personnalise . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.4.2 Classe Adapter perso, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.4.3 Mthode getView personnalise . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.4.4 Mthode PlaneteView.create . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.4.5 Layout ditem res/layout/item_planete.xml . . . . . . . . . . . . . . . . . 71
4.4.6 Classe personnalise dans les ressources . . . . . . . . . . . . . . . . . . . . . 72

6
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

4.4.7 Classe PlaneteView pour afficher les items . . . . . . . . . . . . . . . . . . . 72


4.4.8 Dfinition de la classe PlaneteView . . . . . . . . . . . . . . . . . . . . . . . 72
4.4.9 Crer des vues partir dun layout XML . . . . . . . . . . . . . . . . . . . . 73
4.4.10 Mthode PlaneteView.create . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.4.11 Mthode findViews . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4.4.12 Pour finir, la mthode PlaneteView.display . . . . . . . . . . . . . . . . . 74
4.4.13 Rcapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.4.14 Le rsultat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.5 Actions utilisateur sur la liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.5.1 Modification des donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.5.2 Clic sur un lment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.5.3 Clic sur un lment, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.5.4 Clic sur un lment, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.5.5 Clic sur un lment, fin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.5.6 Liste dlments cochables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.5.7 Liste cochable simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.5.8 Liste choix multiples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.5.9 Liste cochable personnalise . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.5.10 Ouf, cest fini . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

5 Ergonomie 79
5.1 Barre daction et menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
5.1.1 Barre daction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
5.1.2 Ralisation dun menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
5.1.3 Spcification dun menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.1.4 Icnes pour les menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.1.5 Thme pour une barre daction . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.1.6 couteurs pour les menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.1.7 Ractions aux slections ditems . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.1.8 Menus en cascade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
5.1.9 Menus contextuels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.1.10 Associer un menu contextuel une vue . . . . . . . . . . . . . . . . . . . . . 82
5.1.11 Callback daffichage du menu . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.1.12 Callback des items du menu . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

7
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

5.2 Annonces et dialogues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83


5.2.1 Annonces : toasts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.2.2 Annonces personnalises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
5.2.3 Dialogues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
5.2.4 Dialogue dalerte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
5.2.5 Boutons et affichage dun dialogue dalerte . . . . . . . . . . . . . . . . . . . 85
5.2.6 Autres types de dialogues dalerte . . . . . . . . . . . . . . . . . . . . . . . . 85
5.2.7 Dialogues personnaliss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
5.2.8 Cration dun dialogue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.2.9 Affichage du dialogue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
5.3 Fragments et activits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.3.1 Fragments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.3.2 Tablettes, smartphones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.3.3 Structure dun fragment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
5.3.4 Diffrents types de fragments . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
5.3.5 Cycle de vie des fragments . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
5.3.6 ListFragment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
5.3.7 ListFragment, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
5.3.8 Menus de fragments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
5.3.9 Intgrer un fragment dans une activit . . . . . . . . . . . . . . . . . . . . . 90
5.3.10 Fragments statiques dans une activit . . . . . . . . . . . . . . . . . . . . . . 90
5.3.11 FragmentManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
5.3.12 Attribution dun fragment dynamiquement . . . . . . . . . . . . . . . . . . . 90
5.3.13 Disposition selon la gomtrie de lcran . . . . . . . . . . . . . . . . . . . . 91
5.3.14 Changer la disposition selon la gomtrie . . . . . . . . . . . . . . . . . . . . 91
5.3.15 Deux dispositions possibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
5.3.16 Communication entre Activit et Fragments . . . . . . . . . . . . . . . . . . 92
5.3.17 Interface pour un couteur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
5.3.18 couteur du fragment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.3.19 couteur de lactivit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.3.20 Relation entre deux classes mditer, partie 1 . . . . . . . . . . . . . . . . . 94
5.3.21 mditer, partie 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
5.4 Prfrences dapplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
5.4.1 Illustration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

8
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

5.4.2 Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
5.4.3 Dfinition des prfrences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
5.4.4 Explications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
5.4.5 Accs aux prfrences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5.4.6 Prfrences chanes et nombres . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5.4.7 Modification des prfrences par programme . . . . . . . . . . . . . . . . . . 96
5.4.8 Affichage des prfrences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.4.9 Fragment pour les prfrences . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.5 Bibliothque support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.5.1 Compatibilit des applications . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.5.2 Compatibilit des versions Android . . . . . . . . . . . . . . . . . . . . . . . 98
5.5.3 Bibliothque support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
5.5.4 Versions de lAndroid Support Library . . . . . . . . . . . . . . . . . . . . . 98
5.5.5 Mode demploi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
5.5.6 Programmation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
5.5.7 Il est temps de faire une pause . . . . . . . . . . . . . . . . . . . . . . . . . . 99

6 Bases de donnes SQLite3 <> 100


6.1 SQLite3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.1.1 Stockage dinformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.1.2 SQLite3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.1.3 Exemples SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.1.4 Autres usages de SQLite3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.1.5 Lancement de sqlite3 en shell . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.1.6 Commandes internes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
6.2 SQLite dans une application Android . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
6.2.1 Bases de donnes Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
6.2.2 Classes pour travailler avec SQLite . . . . . . . . . . . . . . . . . . . . . . . 102
6.2.3 tapes du travail avec une BDD . . . . . . . . . . . . . . . . . . . . . . . . . 102
6.2.4 Base ouverte dans une activit . . . . . . . . . . . . . . . . . . . . . . . . . . 103
6.2.5 Patron de conception pour les requtes . . . . . . . . . . . . . . . . . . . . . 103
6.2.6 Noms des colonnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
6.2.7 Classe pour une table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
6.2.8 Exemples de mthodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

9
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.2.9 Mthodes SQLiteDatabase.execSQL . . . . . . . . . . . . . . . . . . . . . . 105


6.2.10 Mthodes spcialises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
6.2.11 Mthode insert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
6.2.12 Mthodes update et delete . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.2.13 Mthode rawQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.2.14 rawQuery pour un seul n-uplet . . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.2.15 Classe Cursor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
6.2.16 Exemple de requte, classe TablePlanetes . . . . . . . . . . . . . . . . . . . 107
6.2.17 Autre type de requte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
6.2.18 Mthodes query : sans aucun intrt . . . . . . . . . . . . . . . . . . . . . . 108
6.2.19 Ouverture dune base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
6.2.20 Premire ouverture et ouvertures suivantes . . . . . . . . . . . . . . . . . . . 108
6.2.21 Un helper pour grer louverture/cration/mj . . . . . . . . . . . . . . . . . 108
6.2.22 Exemple de helper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.2.23 Exemple de helper, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.2.24 mthode onUpgrade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
6.2.25 mthode onUpgrade, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
6.2.26 Retour lapplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
6.3 CursorAdapter et Loaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
6.3.1 Lien entre une BDD et un ListView . . . . . . . . . . . . . . . . . . . . . . . 111
6.3.2 tapes suivre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
6.3.3 Activit ou fragment daffichage dune liste . . . . . . . . . . . . . . . . . . . 111
6.3.4 Cration dun adaptateur de curseur . . . . . . . . . . . . . . . . . . . . . . . 112
6.3.5 Ouverture de la base et cration dun chargeur . . . . . . . . . . . . . . . . . 112
6.3.6 Callback onCreateLoader de lactivit . . . . . . . . . . . . . . . . . . . . . 112
6.3.7 classe MonCursorLoader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
6.3.8 Callback onLoadFinished de lactivit . . . . . . . . . . . . . . . . . . . . . 113
6.3.9 Mise jour de la liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
6.3.10 En mode compatibilit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.4 ContentProviders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.4.1 Prsentation rapide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.5 WebServices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.5.1 Base de donne distante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.5.2 change entre un serveur SQL et une application Android . . . . . . . . . . . 114

10
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.5.3 Principe gnral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115


6.5.4 Exemple de script PHP Post . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
6.5.5 Exemple de script PHP Get . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
6.5.6 Format JSON JavaScript Object Notation . . . . . . . . . . . . . . . . . . . . 116
6.5.7 JSON en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
6.5.8 Dans lapplication Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
6.5.9 Affichage dune liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
6.5.10 La classe RemoteDatabase . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
6.5.11 Modification dun n-uplet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
6.5.12 Script update_planete.php . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
6.5.13 Mthode post(couteur, script, params) . . . . . . . . . . . . . . . . . . 118
6.5.14 Principe de la mthode post . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
6.5.15 Cest tout pour aujourdhui . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

7 Affichage de donnes golocalises 119


7.1 AsyncTasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
7.1.1 Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
7.1.2 Tches asynchrones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
7.1.3 Principe dutilisation dune AsyncTask . . . . . . . . . . . . . . . . . . . . . 120
7.1.4 Structure dune AsyncTask . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
7.1.5 Paramtres dune AsyncTask . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
7.1.6 Exemple de paramtrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
7.1.7 Paramtres variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
7.1.8 Dfinition dune AsyncTask . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
7.1.9 AsyncTask, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
7.1.10 Lancement dune AsyncTask . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
7.1.11 Schma rcapitulatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
7.1.12 execute ne retourne rien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
7.1.13 Rcupration du rsultat dun AsyncTask . . . . . . . . . . . . . . . . . . . . 123
7.1.14 Simplification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
7.1.15 Recommandations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
7.1.16 Autres tches asynchrones . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
7.2 Requtes HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
7.2.1 Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

11
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

7.2.2 Principe de programmation pour un GET . . . . . . . . . . . . . . . . . . . . 125


7.2.3 Exemple de requte GET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
7.2.4 Encodage de paramtres pour une requte . . . . . . . . . . . . . . . . . . . 125
7.2.5 Principe de programmation pour un POST . . . . . . . . . . . . . . . . . . . 126
7.2.6 Exemple de requte POST . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
7.2.7 Requtes asynchones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
7.2.8 Permissions pour lapplication . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.3 OpenStreetMap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.3.1 Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.3.2 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.3.3 Pour commencer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.3.4 Layout pour une carte OSM . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.3.5 Activit pour une carte OSM . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
7.3.6 Positionnement de la vue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
7.3.7 Calques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
7.3.8 Mise jour de la carte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
7.3.9 Marqueurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
7.3.10 Marqueur personnaliss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
7.3.11 Raction un clic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7.3.12 Itinraires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7.3.13 Position GPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7.3.14 Mise jour en temps rel de la position . . . . . . . . . . . . . . . . . . . . . 132
7.3.15 Positions simules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
7.3.16 Clics sur la carte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
7.3.17 Traitement des clics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
7.3.18 Autorisations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
7.3.19 Voil tout pour cette semaine . . . . . . . . . . . . . . . . . . . . . . . . . . 134

8 Dessin 2D interactif 135


8.1 Dessin en 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
8.1.1 Principes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
8.1.2 Layout pour le dessin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
8.1.3 Mthode onDraw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
8.1.4 Mthodes de la classe Canvas . . . . . . . . . . . . . . . . . . . . . . . . . . 136

12
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

8.1.5 Peinture Paint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137


8.1.6 Quelques accesseurs de Paint . . . . . . . . . . . . . . . . . . . . . . . . . . 137
8.1.7 Motifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
8.1.8 Shaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
8.1.9 Shaders, suite et fin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
8.1.10 Quelques remarques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
8.1.11 Dessinables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
8.1.12 Images PNG tirables 9patch . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
8.1.13 Drawable, suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
8.1.14 Variantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
8.1.15 Utilisation dun Drawable . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
8.1.16 Enregistrer un dessin dans un fichier . . . . . . . . . . . . . . . . . . . . . . . 140
8.1.17 Coordonnes dans un canvas . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
8.2 Interactions avec lutilisateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
8.2.1 couteurs pour les touchers de lcran . . . . . . . . . . . . . . . . . . . . . . 141
8.2.2 Modle de gestion des actions . . . . . . . . . . . . . . . . . . . . . . . . . . 141
8.2.3 Automate pour grer les actions . . . . . . . . . . . . . . . . . . . . . . . . . 142
8.3 Botes de dialogue spcifiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
8.3.1 Slecteur de couleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
8.3.2 Version simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
8.3.3 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
8.3.4 Fragment de dialogue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
8.3.5 Mthode onCreateDialog . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
8.3.6 Vue personnalise dans le dialogue . . . . . . . . . . . . . . . . . . . . . . . . 144
8.3.7 Layout de cette vue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
8.3.8 Utilisation du dialogue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
8.3.9 Slecteur de fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
8.3.10 Cest la fin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

13
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Semaine 1

Environnement de dveloppement

Le cours de cette semaine prsente lenvironnement de dveloppement Android :


Le SDK Android et Android Studio
Cration dune application simple
Communication avec une tablette.

1.1. Introduction
1.1.1. Android

n en 2004,
rachet par Google en 2005,
publi en 2007, version 1.5,
de nombreuses versions depuis, on en est la 7.1.1 (janvier 2017).

1.1.2. Dfinition
Systme complet pour smartphones et tablettes
Gestion matrielle : systme dexploitation Linux sous-jacent
API de programmation : interfaces utilisateur, outils. . .
Applications : navigateur, courrier. . .
volution et obsolescence trs rapides (cest voulu)
Ce que vous allez apprendre sera rapidement dpass (1 an)
syntaxiquement (mthodes, paramtres, classes, ressources. . . )
mais pas les concepts (principes, organisation. . . )
Vous tes condamn(e) une autoformation permanente, mais cest le lot des informaticiens.

14
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 1: Constituants dAndroid

15
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

1.1.3. Composants dAndroid


Voir la figure 1, page 15.

1.1.4. Programmation dapplications


Une application Android est compose de :
Sources Java compils pour une machine virtuelle Dalvik (versions 4.4) ou ART
depuis la version 5
Fichiers XML appels ressources : interface, textes. . .
Fichiers de donnes supplmentaires
Manifeste = description du contenu du logiciel
fichiers prsents dans larchive
demandes dautorisations
signature des fichiers, dure de validit, etc.
Tout cet ensemble est gr laide dun IDE (environnement de dveloppement) appel Android
Studio et dun ensemble logiciel (bibliothques, outils) appel SDK Android.

1.2. SDK Android et Android Studio


1.2.1. SDK et Studio
Le SDK contient :
les librairies Java pour crer des logiciels
les outils de mise en bote des logiciels
un mulateur de tablettes pour tester les applications AVD
un outil de communication avec les vraies tablettes ADB
Android Studio offre :
un diteur de sources
des outils de compilation et de lancement dAVD

1.2.2. SDK Manager


Le SDK est livr avec un gestionnaire. Cest une application qui permet de choisir les composants
installer.
Voir la figure 2, page 17.

1.2.3. Choix des lments du SDK


Tlcharger le SDK correspondant au systme dexploitation. Ce SDK contient un gestionnaire (SDK
Manager).
Le gestionnaire permet de choisir les versions2 installer :
1
Certaines images de ce cours sont de http://developer.android.com
2
versions existantes la date de rdaction de ce cours

16
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 2: Gestionnaire de paquets Android

Android 7.1.1 (API 25)


Android 7.0 (API 24)
Android 6 (API 23)
Android 5.1.1 (API 22)
Android 4.4W.2 (API 20)
...
Android 1.5 (API 3)
Choisir celles qui correspondent aux tablettes quon vise.

1.2.4. Dossiers du SDK


Le gestionnaire tlcharge environ 800Mo de fichiers :
SDK Tools : indispensable, contient le gestionnaire,
SDK Platform-tools : indispensable, contient adb,
SDK Platform : indispensable, contient les librairies,
System images : pour crer des AVD,
Android Support : divers outils pour crer des applications,
Exemples et sources.
Cest dj install lIUT, mais dans des versions antrieures, correspondant aux tablettes dont on
dispose.

17
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

1.2.5. Android Studio


Pour finir, il faut installer Android Studio selon la procdure explique sur cette page. Il est dj
install lIUT, mais en version un peu plus ancienne.
Aprs cette installation, il faut indiquer lemplacement du SDK dans Android Studio.
Une autre manire est dinstaller Android Studio en premier, lui-mme installant tous les composants
manquants (et mme un peu plus que le ncessaire).

1.3. Premire application


1.3.1. Objectif de la semaine 1
Cette semaine, ce sera seulement un aperu rapide des possibilits :
Cration dune application HelloWorld avec un assistant,
Tour du propritaire,
Excution de lapplication,
Mise sous forme dun paquet.

1.3.2. Assistant de cration dapplication


Android Studio contient un assistant de cration dapplications :
Voir la figure 3, page 19.

1.3.3. Choix de la version


Chaque version dAndroid, dnote par son API level, ex: 25, apporte des amliorations et supprime
des dispositifs obsoltes.
Toute application exige un certain niveau dAPI :
Minimum SDK : il faut au moins cette API car on utilise certaines classes et mthodes absentes
des prcdentes APIs,
Avec Eclipse, on devait aussi spcifier :
Target SDK : lapplication sera teste et marchera correctement jusqu ce niveau dAPI,
Compile With : cest le niveau maximal de fonctionnalits quon se limite employer. Si on
fait appel quelque chose de plus rcent que ce niveau, le logiciel ne se compilera pas.

1.3.4. Choix de la version


Voici comment choisir le Minimum SDK :
Voir la figure 4, page 20.

1.3.5. Choix du type dapplication


Ensuite, on choisit le type de projet. Pour un premier essai, on se limite au plus simple, Blank
Activity :
Voir la figure 5, page 21.

18
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 3: Assistant de cration de projet

19
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 4: Choix de la version

20
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 5: Choix du type dactivit

21
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

1.3.6. Points configurer


Lassistant demande ensuite plusieurs informations :
Nom de lapplication, ex : HelloWorld,
Nom de la classe principale : MainActivity,
Nom du layout de la classe principale : activity_main3 ,
Nom du layout du menu principal : menu_main.
Tout peut tre renomm ultrieurement, voir refactor/rename.
Le package du logiciel a t dfini dans le premier cran.

1.3.7. Noms des packages et classes


Voici o on indique ces informations :

1.3.8. Rsultat de lassistant


Lassistant a cr de nombreux lments visibles dans la colonne de gauche de lIDE :
manifests : description et liste des classes de lapplication
java : les sources, rangs par paquetage,
res : ressources = fichiers XML et images de linterface, il y a des sous-dossiers :
layout : interfaces (disposition des vues sur les crans)
menu : menus contextuels ou dapplication
mipmap et drawable : images, icnes de linterface
values : valeurs de configuration, textes. . .
Gradle scripts : cest loutil de compilation du projet.
NB: on ne va pas chercher comprendre a cette semaine.

1.3.9. Fentre du projet


Voir la figure 7, page 24.

1.3.10. diteurs spcifiques


Les ressources (disposition des vues dans les interfaces, menus, images vectorielles, textes. . . ) sont
dfinies laide de fichiers XML.
Studio fournit des diteurs spcialiss pour ces fichiers, par exemple :
Formulaires pour :
res/values/strings.xml : textes de linterface.
diteurs graphiques pour :
res/layout/*.xml : disposition des contrles sur linterface.

22
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 6: Choix du type dactivit

23
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 7: lments24
dun projet Android
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 8: diteur du manifeste

1.3.11. Exemple res/values/strings.xml


Voir la figure 8, page 25.

1.3.12. Exemple res/layout/main.xml

1.3.13. Source XML sous-jacent


Ces diteurs sont beaucoup plus confortables que le XML brut, mais ne permettent pas de tout faire
(et plantent souvent parfois).
Dans certains cas, il faut diter le source XML directement :

<RelativeLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>

Vous avez remarqu le namespace des attributs.

1.3.14. Reconstruction du projet


Automatique :
3
Je naime pas ce nommage invers entre activits TrucActivity et layouts activity_truc, je prfre
truc_activity.xml. Mme remarque pour les menus, main_menu au lieu de menu_main. a permet dorganiser
les ressources par activits, main_activity, main_menu. . . , et non par catgories.

25
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 9: diteur graphique

26
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Ex: modifier le fichier res/values/strings.xml ou un source Java,


Gradle compile automatiquement le projet.
Manuelle, parfois ncessaire quand on modifie certaines ressources :
Slectionner le projet et choisir menu Build/Clean...
Ces actions lancent lexcution de Gradle.

1.3.15. Gradle
Gradle est un outil de construction de projets comme Make (projets C++ sur Unix), Ant (projets Java
dans Eclipse) et Maven. Il se sert dun (ou plusieurs) script build.gradle qui indique la structure
du projet.
Un projet AndroidStudio est constitu de :
dossier app qui contient src/main qui lui-mme contient java, res et le manifeste
dossier build pour les fichiers intermdiaires (.class et autres)
des fichiers de configuration de gradle :
local.properties : chemin daccs au SDK
build.gradle : structure du projet

1.3.16. Gradle en ligne de commande


Parmi les fichiers et dossiers, il y a galement :
un script bash gradlew qui appelle gradle proprement
dossier gradle qui contient larchive jar permettant de lancer gradlew
Il suffit de taper :
gradlew clean : suppression du dossier build
gradlew assembleDebug : compilation du projet, en version debug, assembleRelease pour la
version publique
gradlew build : compile et teste lapplication
gradlew installDebug : compilation et installation
gradlew tasks : liste des cibles possibles.

1.4. Premire excution


1.4.1. Excution de lapplication
Le SDK Android permet de :
Installer lapplication sur une vraie tablette connecte par USB
Simuler lapplication sur une tablette virtuelle AVD
AVD = Android Virtual Device
Cest une machine virtuelle comme celles de VirtualBox et VMware, mais base sur QEMU.
QEMU est en licence GPL, il permet dmuler toutes sortes de CPU dont des ARM7, ceux qui font
tourner la plupart des tablettes Android.

27
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

1.4.2. Assistant de cration dune tablette virtuelle

Figure 10: Cration dun AVD

1.4.3. Caractristiques dun AVD


Lassistant de cration de tablette demande :
Modle de tablette ou tlphone simuler,
Version du systme quil doit contenir,
Orientation et densit de lcran
Options de simulation :
Snapshot : mmorise ltat de la machine dun lancement lautre, mais exclut Use
Host GPU,
Use Host GPU : acclre les dessins 2D et 3D laide de la carte graphique du PC.
Options avances :
RAM : mmoire allouer, mais est limite par votre PC,
Internal storage : capacit de la flash interne,

28
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

SD Card : capacit de la carte SD simule supplmentaire (optionnelle).

1.4.4. Lancement dune application


Bouton vert pour excuter, bleu pour dboguer :

Figure 11: Barre doutils pour lancer une application

1.4.5. Application sur lAVD

Figure 12: Rsultat sur lAVD


Lapparence change dune version lautre du SDK.

1.4.6. Contrle de lAVD


Pour simuler les boutons dune vraie tablette :
CTRL-M affiche le menu de lapplication
CTRL-backspace retour en arrire
home retour lcran daccueil
ctrl-left ctrl-right rotation paysage/portrait avec les flches du clavier.

29
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

1.5. Communication AVD - Android Studio


1.5.1. Fentres Android
Android Studio affiche plusieurs fentres utiles indiques dans longlet tout en bas :
Android Monitor Affiche tous les messages mis par la tablette courante
Console Messages du compilateur et du studio

1.5.2. Fentre LogCat


Des messages dtaills sont affichs dans la fentre LogCat :

Figure 13: Fentre LogCat

Ils sont mis par les applications : debug, infos, erreurs. . .

1.5.3. Filtrage des messages


Il est commode de dfinir des filtres pour ne pas voir la totalit des messages de toutes les applications
de la tablette :
sur le niveau de gravit : verbose, debug, info, warn, error et assert,
sur ltiquette TAG associe chaque message,
sur le package de lapplication qui met le message.

1.5.4. mission dun message pour LogCat


Une application met un message par ces instructions :
import android.util.Log;
public class MainActivity extends Activity {
public static final String TAG = "hello";
void maMethode() {
Log.i(TAG, "Salut !");

30
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Fonctions Log.* :
Log.i(String tag, String message) affiche une info,
Log.w(String tag, String message) affiche un avertissement,
Log.e(String tag, String message) affiche une erreur.

1.5.5. Logiciel ADB


Android Debug Bridge est une passerelle entre une tablette (relle ou virtuelle) et votre PC
Serveur de connexion des tablettes
Commande de communication
ADB emprunte FTP (transfert de fichiers) et SSH (connexion un shell).

1.5.6. Mode demploi de ADB


En ligne de commande : adb commande paramtres...
Gestion du serveur
adb start-server : dmarre le serveur,
adb kill-server : arrte le serveur,
adb devices : liste les tablettes connectes.
Exemple :

~/CoursAndroid/$ adb devices


List of devices attached
emulator-5554 device
c1608df1b170d4f device
~/CoursAndroid/$

1.5.7. Mode demploi, suite


Chaque tablette (device) possde un identifiant, ex: c1608df1b170d4f ou emulator-5554 quil faut
fournir aux commandes adb laide de loption -s.
Par dfaut, cest la seule tablette active qui est concerne.
Connexion un shell
adb -s identifiant shell commande_unix. . .
excute la commande sur la tablette
adb -s identifiant shell
ouvre une connexion de type shell sur la tablette.
Ce shell est un interprteur sh simplifi (type busybox) lintrieur du systme Unix de la tablette. Il
connat les commandes standard Unix de base : ls, cd, cp, mv, ps. . .

1.5.8. Systme de fichiers Android


On retrouve larchitecture des dossiers Unix, avec des variantes :
Dossiers Unix classiques : /usr, /dev, /etc, /lib, /sbin. . .

31
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Les volumes sont monts dans /mnt, par exemple /mnt/sdcard (mmoire flash interne) et
/mnt/extSdCard (SDcard amovible)
Les applications sont dans :
/system/app pour les pr-installes
/data/app pour les applications normales
Les donnes des applications sont dans /data/data/nom.du.paquetage.java
Ex: /data/data/fr.iutlan.helloworld/. . .
NB : il y a des restrictions daccs sur une vraie tablette, car vous ny tes pas root . . . enfin en
principe.

1.5.9. Mode demploi, suite


Pour changer des fichiers avec une tablette :
adb push nom_du_fichier_local /nom/complet/dest
envoi du fichier local sur la tablette
adb pull /nom/complet/fichier
rcupre ce fichier de la tablette
Pour grer les logiciels installs :
adb install paquet.apk
adb uninstall nom.du.paquetage.java
Pour archiver les donnes de logiciels :
adb backup -f fichier_local nom.du.paquetage.java . . .
enregistre les donnes du/des logiciels dans le fichier local
adb restore fichier_local
restaure les donnes du/des logiciels daprs le fichier.

1.6. Cration dun paquet installable


1.6.1. Paquet
Un paquet Android est un fichier .apk. Cest une archive signe (authentifie) contenant les binaires,
ressources compresses et autres fichiers de donnes.
La cration est relativement simple avec Studio :
1. Menu contextuel du projet Build..., choisir Generate Signed APK,
2. Signer le paquet laide dune cl prive,
3. Dfinir lemplacement du fichier .apk.
Le rsultat est un fichier .apk dans le dossier spcifi.

1.6.2. Signature dune application


Lors de la mise au point, Studio gnre une cl qui ne permet pas dinstaller lapplication ailleurs.
Pour distribuer une application, il faut une cl prive.
Les cls sont stockes dans un keystore = trousseau de cls. Il faut le crer la premire fois. Cest un
fichier crypt, protg par un mot de passe, ranger soigneusement.
Ensuite crer une cl prive :

32
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

alias = nom de la cl, mot de passe de la cl


informations personnelles compltes : prnom, nom, organisation, adresse, etc.
Les mots de passe du trousseau et de la cl seront demands chaque cration dun .apk.

1.6.3. Cration du keystore

Figure 14: Cration dun trousseau de cls

1.6.4. Cration dune cl

1.6.5. Cration du paquet


Ensuite, Studio demande o placer le .apk :
Voir la figure 16, page 34.

1.6.6. Et voil
Cest fini pour cette semaine, rendez-vous la semaine prochaine pour un cours sur les interfaces
Android.

33
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 15: Cration dune cl

34
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 16: Cration du paquet

Semaine 2

Cration dinterfaces utilisateur

Le cours de cette semaine explique la cration dinterfaces utilisateur :


Relations entre un source Java et des ressources
Layouts et vues
Styles
On ne sintresse qu la mise en page. Lactivit des interfaces sera tudie la semaine prochaine.
NB: les textes fuchsia sont des liens cliquables.

2.1. Interface et ressources


2.1.1. Activits
Linterface utilisateur dune application Android est compose dcrans. Un cran correspond une
activit, ex :

35
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

afficher une liste ditems


diter un item laide dun formulaire.
Les dialogues et les pop-up ne sont pas des activits, ils se superposent temporairement lcran
dune activit.
Android permet de naviguer dune activit lautre, ex :
une action de lutilisateur, bouton, menu ou lapplication fait aller sur lcran suivant
le bouton back ramne sur lcran prcdent.

2.1.2. Cration dun cran


Chaque cran est gr par une instance dune sous-classe perso de Activity. Sa mthode onCreate
dfinit, entre autres, ce qui doit tre affich sur lcran :

public class MainActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}

@Override signifie que onCreate surcharge cette mthode de la superclasse et il faut aussi lappeler
sur super

2.1.3. Identifiant de ressource


La mthode setContentView spcifie lidentifiant de linterface afficher dans lcran :
R.layout.main. Cest un entier, identifiant dune disposition de vues : un layout.
Le SDK Android (aapt) construit automatiquement une classe statique appele R. Elle ne contient
que des constantes entires :

package fr.iutlan.helloworld;
public final class R {
public static final class id {
public static final int texte=0x7f080000;
}
public static final class layout {
public static final int main=0x7f030000;
}

2.1.4. La classe R
Cette classe R est gnre automatiquement par ce que vous mettez dans le dossier res : dispositions,
identifiants, chanes. . . Certaines de ces ressources sont des fichiers XML, dautres sont des images
PNG.
Par exemple, res/values/strings.xml :

36
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

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


<resources>
<string name="app_name">Exemple</string>
<string name="message">Bonjour !</string>
<resources>

2.1.5. Rappel sur la structure dun fichier XML


Un fichier XML : nuds racine, lments, attributs, valeurs, texte.

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


<racine>
<!-- commentaire -->
<element attribut1="valeur1"
attribut2="valeur2">
<feuille1 attribut3="valeur3"/>
<feuille2>texte</feuille2>
</element>
texte en vrac
</racine>

Voir le cours XML.

2.1.6. Espaces de nommage dans un fichier XML


Dans le cas dAndroid, il y a un grand nombre dlments et dattributs normaliss. Pour les distinguer,
ils ont t regroups dans le namespace android. Dans la norme XML, le namespace par dfaut nest
jamais appliqu aux attributs, donc il faut mettre le prfixe sur chacun deux.
Vous pouvez lire cette page et celle-ci sur les namespaces.

<menu xmlns:android=
"http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="Configuration"/>
</menu>

2.1.7. Cration dune interface par programme


Il est possible de crer une interface par programme, mais cest assez compliqu :

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);
Context ctx = getApplicationContext();

37
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

TextView tv = new TextView(ctx);


tv.setText("Demat !");
RelativeLayout rl = new RelativeLayout(ctx);
LayoutParams lp = new LayoutParams();
lp.width = LayoutParams.MATCH_PARENT;
lp.height = LayoutParams.MATCH_PARENT;
rl.addView(tv, lp);
setContentView(rl);
}

2.1.8. Programme et ressources


Il est donc prfrable de stocker linterface dans un fichier res/layout/main.xml :

<RelativeLayout ...>
<TextView android:text="Demat !" ... />
</RelativeLayout>

qui est rfrenc par son identifiant R.layout.nom_du_fichier (ici cest main) dans le programme
Java :

protected void onCreate(Bundle bundle) {


super.onCreate(bundle);
setContentView(R.layout.main);
}

2.1.9. Ressources de type chanes


Dans res/values/strings.xml, on place les chanes de lapplication, au lieu de les mettre en
constantes dans le source :

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


<resources>
<string name="app_name">HelloWorld</string>
<string name="main_menu">Menu principal</string>
<string name="action_settings">Configuration</string>
<string name="bonjour">Demat !</string>
</resources>

Intrt : pouvoir traduire une application sans la recompiler.

2.1.10. Traduction des chanes (localisation)


Lorsque les textes sont dfinis dans res/values/strings.xml, il suffit de faire des copies du dossier
values, en values-us, values-fr, values-de, etc. et de traduire les textes en gardant les attributs
name. Voici par exemple res/values-de/strings.xml :

38
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

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


<resources>
<string name="app_name">HelloWorld</string>
<string name="main_menu">Hauptmen</string>
<string name="action_settings">Einstellungen</string>
<string name="bonjour">Guten Tag</string>
</resources>

Le systme android ira chercher automatiquement le bon texte en fonction des paramtres linguistiques
configurs par lutilisateur.

2.1.11. Rfrencement des ressources texte


Voici comment affecter une ressource chane une vue en Java :

TextView tv = new TextView(ctx);


tv.setText(R.string.bonjour);

R.string.bonjour dsigne le texte de <string name="bonjour">... dans le fichier res/values*/strings.x


Voici comment spcifier un titre de label dans un layout.xml :

<RelativeLayout>
<TextView android:text="@string/bonjour" />
</RelativeLayout>

@string/nom est une rfrence une ressource, la chane de res/values/strings.xml ayant ce nom.

2.1.12. Identifiants et vues


La mthode setContentView fait afficher le formulaire dfini par lidentifiant R.layout indiqu.
Lorsque lapplication veut manipuler lune de ses vues, elle doit faire utiliser R.id.symbole, ex :

TextView tv = (TextView) findViewById(R.id.message);

NB: remarquez la conversion de type, findViewById retourne une View, superclasse de TextView.
avec la dfinition suivante dans res/layout/main.xml :

<RelativeLayout>
<TextView android:id="@+id/message"
android:text="@string/bonjour" />
</RelativeLayout>

La notation @+id/nom dfinit un identifiant pour le TextView.

39
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

2.1.13. @id/nom ou @+id/nom ?


Il y a les deux notations :
@id/nom pour rfrencer un identifiant dj dfini (ailleurs)
@+id/nom pour dfinir (crer) cet identifiant
Exemple, le Button btn dsigne le TextView titre :

<RelativeLayout xmlns:android="..." ... >


<TextView ...
android:id="@+id/titre"
android:text="@string/titre" />
<Button ...
android:id="@+id/btn"
android:layout_below="@id/titre"
android:text="@string/ok" />
</RelativeLayout>

2.1.14. Images : R.drawable.nom


De la mme faon, les images PNG places dans res/drawable et res/mipmaps-* sont rfrenables :

<ImageView
android:src="@drawable/velo"
android:contentDescription="@string/mon_velo" />

La notation @drawable/nom rfrence limage portant ce nom dans lun des dossiers.
NB: les dossiers res/mipmaps-* contiennent la mme image des dfinitions diffrentes, pour
correspondre diffrents tlphones et tablettes. Ex: mipmap-hdpi contient des icnes en 72x72
pixels.

2.1.15. Tableau de chanes : R.array.nom


Voici un extrait du fichier res/strings/arrays.xml :

<resources>
<string-array name="planetes">
<item>Mercure</item>
<item>Venus</item>
<item>Terre</item>
<item>Mars</item>
</string-array>
</resources>

Dans le programme Java, il est possible de faire :

40
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Resources res = getResources();


String[] planetes = res.getStringArray(R.array.planetes);

2.1.16. Autres
Dautres notations existent :
@style/nom pour des dfinitions de res/style
@menu/nom pour des dfinitions de res/menu
Certaines notations, @package:type/nom font rfrence des donnes prdfinies, comme :
@android:style/TextAppearance.Large
@android:color/black
Il y a aussi une notation en ?type/nom pour rfrencer la valeur de lattribut nom, ex :
?android:attr/textColorSecondary.

2.2. Dispositions
2.2.1. Structure dune interface Android
Un cran Android de type formulaire est gnralement compos de plusieurs vues. Entre autres :
TextView, ImageView titre, image
EditText texte saisir
Button, CheckBox bouton cliquer, case cocher
Ces vues sont alignes laide de groupes sous-classes de ViewGroup, ventuellement imbriqus :
LinearLayout positionne ses vues en ligne ou colonne
RelativeLayout positionne ses vues lune par rapport lautre
TableLayout positionne ses vues sous forme dun tableau

2.2.2. Arbre des vues


Les groupes et vues forment un arbre :

2.2.3. Reprsentation en XML


Cet arbre scrit en XML :

<LinearLayout android:id="@+id/groupe1" ...>


<TextView android:id="@+id/titre" .../>
<EditText android:id="@+id/saisie" .../>
<LinearLayout android:id="@+id/groupe2" ...>
<Button android:id="@+id/ok" .../>
<Button android:id="@+id/raz" .../>
<Button android:id="@+id/annuler" .../>
</LinearLayout>
</LinearLayout>

41
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 17: Arbre de vues

2.2.4. Paramtres de positionnement


La plupart des groupes utilisent des paramtres de placement sous forme dattributs XML. Par
exemple, telle vue droite de telle autre, telle vue la plus grande possible, telle autre la plus petite.
Ces paramtres sont de deux sortes :
ceux qui sont demands pour toutes les vues, par exemple android:layout_width,
android:layout_height et android:layout_weight
ceux qui sont demands par le groupe englobant et qui en sont spcifiques, comme
android:layout_alignParentBottom, android:layout_centerInParent. . .

2.2.5. Paramtres gnraux


Toutes les vues doivent spcifier ces deux attributs :
android:layout_width largeur de la vue
android:layout_height hauteur de la vue
Ils peuvent valoir :
"wrap_content" : la vue est la plus petite possible
"match_parent" : la vue est la plus grande possible
"valeurdp" : une taille fixe, ex : "100dp" mais cest peu recommand
Les dp sont une unit de taille indpendante de lcran. 100dp font 100 pixels sur un cran de 100 dpi
(100 dots per inch) tandis quils font 200 pixels sur un cran 200dpi. a fait la mme taille apparente.

2.2.6. Autres paramtres gomtriques


Il est possible de modifier lespacement des vues :
Padding espace entre le texte et les bords, gr par chaque vue
Margin espace autour des bords, gr par les groupes

42
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 18: Bords et marges

2.2.7. Marges et remplissage


On peut dfinir les marges et les remplissages sparment sur chaque bord (Top, Bottom, Left, Right),
ou identiquement sur tous :

<Button
android:layout_margin="10dp"
android:layout_marginTop="15dp"
android:padding="10dp"
android:paddingLeft="20dp" />

2.2.8. Groupe de vues LinearLayout


Il range ses vues soit horizontalement, soit verticalement

<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:text="Ok" android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button android:text="Annuler" android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

Il faut seulement dfinir lattribut android:orientation "horizontal" ou "vertical". Lire la


doc Android.

2.2.9. Pondration des tailles


Une faon intressante de spcifier les tailles des vues dans un LinearLayout consiste leur affecter
un poids avec lattribut android:layout_weight.
Un layout_weight gal 0 rend la vue la plus petite possible
Un layout_weight non nul donne une taille correspondant au rapport entre ce poids et la
somme des poids des autres vues

43
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Pour cela, il faut aussi fixer la taille de ces vues (ex : android:layout_width) soit "wrap_content",
soit "0dp". Si la taille vaut "wrap_content", alors le poids agit seulement sur lespace supplmentaire
allou aux vues. Mettre 0dp pour que a agisse sur la taille entire.

2.2.10. Exemple de poids diffrents


Voici 4 LinearLayout horizontaux de 3 boutons ayant des poids gaux leurs titres. En 3e ligne, les
boutons ont une largeur de 0dp

Figure 19: Influence des poids sur la largeur

2.2.11. Groupe de vues TableLayout


Cest une variante du LinearLayout : les vues sont ranges en lignes de colonnes bien tabules. Il
faut construire une structure XML comme celle-ci. Voir sa doc Android.

<TableLayout ...>
<TableRow>
<item 1.1 .../>
<item 1.2 .../>
</TableRow>
<TableRow>
<item 2.1 .../>
<item 2.2 .../>
</TableRow>
<TableLayout>

NB : les <TableRow> nont aucun attribut.

44
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

2.2.12. Largeur des colonnes dun TableLayout


Ne pas spcifier android:layout_width dans les vues dun TableLayout, car cest obligatoirement
toute la largeur du tableau. Seul la balise <TableLayout> exige cet attribut.
Deux proprits intressantes permettent de rendre certaines colonnes tirables. Fournir les numros
(premire = 0).
android:stretchColumns : numros des colonnes tirables
android:shrinkColumns : numros des colonnes reductibles

<TableLayout
android:stretchColumns="1,2"
android:shrinkColumns="0,3"
android:layout_width="match_parent"
android:layout_height="wrap_content" >

2.2.13. Groupe de vues RelativeLayout


Cest le plus complexe utiliser mais il donne de bons rsultats. Il permet de spcifier la position
relative de chaque vue laide de paramtres complexes : (LayoutParams)
Tel bord align sur le bord du parent ou centr dans son parent :
android:layout_alignParentTop, android:layout_centerVertical. . .
Tel bord align sur le bord oppos dune autre vue :
android:layout_toRightOf, android:layout_above, android:layout_below. . .
Tel bord align sur le mme bord dune autre vue :
android:layout_alignLeft, android:layout_alignTop. . .

2.2.14. Utilisation dun RelativeLayout


Pour bien utiliser un RelativeLayout, il faut commencer par dfinir les vues qui ne dpendent que
des bords du Layout : celles qui sont colles aux bords ou centres.

<TextView android:id="@+id/titre"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true" .../>

Puis crer les vues qui dpendent des vues prcdentes.

<EditText android:layout_below="@id/titre"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true" .../>

Et ainsi de suite.

45
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

2.2.15. Autres groupements


Ce sont les sous-classes de ViewGroup galement prsentes dans cette page. Impossible de faire
linventaire dans ce cours. Cest vous daller explorer en fonction de vos besoins.

2.3. Composants dinterface


2.3.1. Vues
Android propose un grand nombre de vues, dcouvrir en TP :
Textes : titres, saisies
Boutons, cases cocher
Curseurs
Beaucoup ont des variantes. Ex: saisie de texte = no de tlphone ou adresse ou texte avec suggestion
ou . . .
Consulter la doc en ligne de toutes ces vues. On les trouve dans le package android.widget.
noter que les vues voluent avec les versions dAndroid, certaines changent, dautres disparaissent.

2.3.2. TextView
Le plus simple, il affiche un texte statique, comme un titre. Son libell est dans lattribut
android:text.

<TextView
android:id="@+id/tvtitre"
android:text="@string/titre"
... />

On peut le changer dynamiquement :

TextView tvTitre = (TextView) findViewById(R.id.tvtitre);


tvTitre.setText("blablabla");

2.3.3. Button

Lune des vues les plus utiles est le Button :

<Button
android:id="@+id/btn_ok"
android:text="@string/ok"
... />

En gnral, on dfinit un identifiant pour chaque vue active, ici : android:id="@+id/btn_ok"


Son titre est dans lattribut android:text.
Voir la semaine prochaine pour son activit : raction un clic.

46
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

2.3.4. Bascules

Les CheckBox sont des cases cocher :

<CheckBox
android:id="@+id/cbx_abonnement_nl"
android:text="@string/abonnement_newsletter"
... />

Les ToggleButton sont une variante : . On peut dfinir le texte actif et le texte inactif avec
android:textOn et android:textOff.

2.3.5. EditText

Un EditText permet de saisir un texte :

<EditText
android:id="@+id/email_address"
android:inputType="textEmailAddress"
... />

Lattribut android:inputType spcifie le type de texte : adresse, tlphone, etc. a dfinit le clavier
qui est propos pour la saisie.
Lire la rfrence Android pour connatre toutes les possibilits.

2.3.6. Autres vues


On reviendra sur toutes ces vues les prochaines semaines, pour prciser les attributs utiles pour une
application. Dautres vues pourront aussi tre employes loccasion.

2.4. Styles
2.4.1. Styles et thmes
Un style permet de modifier lapparence dune vue :
Police de caractres et tailles pour les textes
Couleurs, images. . .
Gomtrie par dfaut des vues : taille, espacement, remplissage. . .
Un thme est un style appliqu toute une activit ou application.
Consulter la documentation Android.

2.4.2. Dfinir un style


Il faut crer un fichier XML dans res/value :

47
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

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


<resources>
<style name="Elegant"
parent="@android:style/TextAppearance.Medium">
<item name="android:textColor">#010101</item>
<item name="android:typeface">serif</item>
</style>
</resources>

Lattribut name identifie le style, et parent le rattache un autre pour hritage des proprits non
dfinies ici. Voir les styles et les thmes prdfinis.

2.4.3. Utiliser un style


Il suffit de le prciser dans la dfinition de la vue :

<TextView
style="@style/Elegant"
android:text="@string/titre" />

2.4.4. Utiliser un thme


Un thme est simplement un style appliqu partout dans lapplication. Cela se spcifie dans le fichier
AndroidManifest.xml :

<application
android:theme="@style/Elegant"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
...>
...
</application>

Attention, si votre style nest pas complet, vous aurez une erreur.

2.4.5. Cest tout


Cest fini pour cette semaine, rendez-vous la semaine prochaine pour un cours sur les couteurs et les
activits.

48
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Semaine 3

Vie dune application

Le cours de cette semaine concerne la vie dune application :


Applications et activits, manifeste : bibliographie
Cycles de vie : voir cette page
Vues, vnements et couteurs : voir ce lien et celui-ci

3.1. Applications et activits


3.1.1. Composition dune application
Une application est compose de plusieurs activits. Chacune gre un cran dinteraction avec
lutilisateur et est dfinie par une classe Java.
Une application complexe peut aussi contenir :
des services : ce sont des processus qui tournent en arrire-plan,
des fournisseurs de contenu : ils reprsentent une sorte de base de donnes, voir la semaine 5,
des rcepteurs dannonces : pour grer des vnements globaux envoys par le systme toutes
les applications.

3.1.2. Dclaration dune application


Le fichier AndroidManifest.xml dclare les lments dune application, avec un . devant le nom des activits

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


<manifest ... >
<application android:icon="@drawable/app_icon.png" ...>
<activity android:name=".MainActivity"
... />
<activity android:name=".EditActivity"
... />
...
</application>
</manifest>

<application> est la seule branche sous la racine <manifest> et ses filles sont des <activity>.

49
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

3.1.3. Scurit des applications


Chaque application est associe un UID (compte utilisateur Unix) unique dans le systme. Ce
compte les protge les unes des autres. Cet UID peut tre dfini dans le fichier AndroidManifest.xml :

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


<manifest ...
android:sharedUserId="fr.iutlan.demos">
...
</manifest>

Dfinir lattribut android:sharedUserId avec une chane identique une autre application, et signer
les deux applications avec le mme certificat, permet lune daccder lautre.

3.1.4. Autorisations dune application


Une application doit dclarer les autorisations dont elle a besoin : accs internet, camra, carnet
dadresse, GPS, etc.
Cela se fait en rajoutant des lements dans le manifeste :

<manifest ... >


<uses-permission
android:name="android.permission.INTERNET" />
...
</manifest>

Consulter cette page pour la liste des permissions existantes.

3.1.5. Dmarrage dune application


Lune des activits est marque comme dmarrable de lextrieur :

<activity android:name=".MainActivity" ...>


<intent-filter>
<action android:name=
"android.intent.action.MAIN" />
<category android:name=
"android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Un <intent-filter> dclare les conditions de dmarrage dune activit, ici il dit que cest lactivit
principale.

50
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

3.1.6. Dmarrage dune activit et Intents


Les activits sont dmarres laide dIntents. Un Intent contient une demande destine une
activit, par exemple, composer un numro de tlphone ou lancer lapplication.
action : spcifie ce que lIntent demande. Il y en a de trs nombreuses :
VIEW pour afficher quelque chose, EDIT pour modifier une information, SEARCH. . .
donnes : selon laction, a peut tre un numro de tlphone, lidentifiant dune information. . .
catgorie : information supplmentaire sur laction, par exemple, ...LAUNCHER pour lancer une
application.
Une application a la possibilit de lancer certaines activits dune autre application, celles qui ont un
intent-filter.

3.1.7. Lancement dune activit par programme


Soit une application contenant deux activits : Activ1 et Activ2. La premire lance la seconde par :

Intent intent = new Intent(this, Activ2.class);


startActivity(intent);

Linstruction startActivity dmarre Activ2. Celle-ci se met devant Activ1 qui se met alors en
sommeil.
Ce bout de code est employ par exemple lorsquun bouton, un menu, etc. est cliqu. Seule contrainte :
que ces deux activits soient dclares dans AndroidManifest.xml.

3.1.8. Lancement dune application Android


Il nest pas possible de montrer toutes les possibilits, mais par exemple, voici comment ouvrir le
navigateur sur un URL spcifique :

String url =
"https://perso.univ-rennes1.fr/pierre.nerzic/Android";
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);

Laction VIEW avec un URI (gnralisation dun URL) est interprte par Android, cela fait ouvrir
automatiquement le navigateur.

3.1.9. Lancement dune activit dune autre application


Soit une seconde application dans le package fr.iutlan.appli2. Une activit peut la lancer ainsi :

intent = new Intent(Intent.ACTION_MAIN);


intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName(
"fr.iutlan.appli2",

51
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

"fr.iutlan.appli2.MainActivity");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Cela consiste crer un Intent daction MAIN et de catgorie LAUNCHER pour la classe MainActivity
de lautre application.

3.2. Applications
3.2.1. Fonctionnement dune application
Au dbut, le systme Android lance lactivit qui est marque action=MAIN et catgorie=LAUNCHER
dans AndroidManifest.xml.
Ensuite, dautres activits peuvent tre dmarres. Chacune se met devant les autres comme sur
une pile. Deux cas sont possibles :
La prcdente activit se termine, on ne revient pas dedans.
Par exemple, une activit o on tape son login et son mot de passe lance lactivit principale et
se termine.
La prcdente activit attend la fin de la nouvelle car elle lui demande un rsultat en retour.
Exemple : une activit de type liste ditems lance une activit pour diter un item quand on
clique longuement dessus, mais attend la fin de ldition pour rafrachir la liste.

3.2.2. Navigation entre activits


Voici un schma illustrant les possibilits de navigation parmi plusieurs activits.

3.2.3. Lancement sans attente


Rappel, pour lancer Activ2 partir de Activ1 :

Intent intent = new Intent(this, Activ2.class);


startActivity(intent);

On peut demander la terminaison de this aprs lancement de Activ2 ainsi :

Intent intent = new Intent(this, Activ2.class);


startActivity(intent);
finish();

finish() fait terminer lactivit courante. Lutilisateur ne pourra pas faire back dessus, car elle
disparat de la pile.

3.2.4. Lancement avec attente de rsultat


Le lancement dune activit avec attente de rsultat est plus complexe. Il faut dfinir un code dappel
RequestCode fourni au lancement.

52
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 20: Navigation parmi les activits dune application

53
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

private static final int APPEL_ACTIV2 = 1;


Intent intent = new Intent(this, Activ2.class);
startActivityForResult(intent, APPEL_ACTIV2);

Ce code identifie lactivit lance, afin de savoir plus tard que cest delle quon revient. Par exemple,
on pourrait lancer au choix plusieurs activits : dition, copie, suppression dinformations. Il faut
pouvoir les distinguer au retour.
Consulter cette page.

3.2.5. Lancement avec attente, suite


Ensuite, il faut dfinir une mthode callback qui est appele lorsquon revient dans notre activit :

@Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data)
{
// uti a fait back
if (resultCode == Activity.RESULT_CANCELED) return;
// selon le code d'appel
switch (requestCode) {
case APPEL_ACTIV2: // on revient de Activ2
...
}
}

3.2.6. Terminaison dune activit


Lactivit lance par la premire peut se terminer pour deux raisons :
Volontairement, en appelant la mthode finish() :

setResult(RESULT_OK);
finish();

cause du bouton back du tlphone, son action revient faire ceci :

setResult(RESULT_CANCELED);
finish();

Dans ces deux cas, on revient dans lactivit appelante (sauf si elle-mme avait fait finish().

3.2.7. Mthode onActivityResult


Quand on revient dans lactivit appelante, Android lui fait excuter cette mthode :
onActivityResult(int requestCode, int resultCode, Intent data)
requestCode est le code dappel de startActivityForResult

54
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

resultCode vaut soit RESULT_CANCELED soit RESULT_OK, voir le transparent prcdent


data est fourni par lactivit appele et qui vient de se terminer.
Ces deux dernires viennent dun appel setResult(resultCode, data)

3.2.8. Transport dinformations dans un Intent


Les Intent servent aussi transporter des informations dune activit lautre : les extras.
Voici comment placer des donnes dans un Intent :

Intent intent =
new Intent(this, DeleteInfoActivity.class);
intent.putExtra("idInfo", idInfo);
intent.putExtra("hiddencopy", hiddencopy);
startActivity(intent);

putExtra(nom, valeur) rajoute un couple (nom, valeur) dans lintent. La valeur doit tre srialis-
able : nombres, chanes et structures simples.

3.2.9. Extraction dinformations dun Intent


Ces instructions rcuprent les donnes dun Intent :

Intent intent = getIntent();


Integer idInfo = intent.getIntExtra("idInfo", -1);
bool hidden = intent.getBooleanExtra("hiddencopy", false);

getIntent() retourne lIntent qui a dmarr cette activit.


getTypeExtra(nom, valeur par dfaut) retourne la valeur de ce nom si elle en fait partie, la
valeur par dfaut sinon.

3.2.10. Contexte dapplication


Pour finir sur les applications, il faut savoir quil y a un objet global vivant pendant tout le
fonctionnement dune application : le contexte dapplication. Voici comment le rcuprer :

Application context = this.getApplicationContext();

Par dfaut, cest un objet neutre ne contenant que des informations Android.
Il est possible de le sous-classer afin de stocker des variables globales de lapplication.

3.2.11. Dfinition dun contexte dapplication


Pour commencer, driver une sous-classe de Application :

55
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

public class MonApplication extends Application


{
// variable globale de l'application
public int varglob;

// initialisation du contexte
@Override
public void onCreate()
{
super.onCreate();
varglob = 3;
}
}

3.2.12. Dfinition dun contexte dapplication, suite


Ensuite, la dclarer dans AndroidManifest.xml, dans lattribut android:name de llment
<application> :

<manifest xmlns:android="..." ...>


<application android:name="MonApplication"
android:icon="@drawable/icon"
android:label="@string/app_name">
...

3.2.13. Dfinition dun contexte dapplication, fin


Enfin, lutiliser dans nimporte laquelle des activits :

// rcuprer le contexte d'application


MonApplication context =
(MonApplication) this.getApplicationContext();

// utiliser la variable globale


... context.varglob ...

Remarquez la conversion de type.


Il est recommand de dfinir des setters et getters. Dautre part, attention aux variables globales : ne
les utiliser qu bon escient.

3.3. Activits
3.3.1. Prsentation
Voyons maintenant comment fonctionnent les activits.
Dmarrage ( cause dun Intent)

56
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Apparition/masquage sur cran


Terminaison
Une activit se trouve dans lun de ces tats :
active (resumed) : elle est sur le devant, lutilisateur peut jouer avec,
en pause (paused) : partiellement cache et inactive, car une autre activit est venue devant,
stoppe (stopped) : totalement invisible et inactive, ses variables sont prserves mais elle ne
tourne plus.

3.3.2. Cycle de vie dune activit


Ce diagramme rsume les changement dtats dune activit :

Figure 21: Cycle de vie

3.3.3. vnements de changement dtat


La classe Activity reoit des vnements de la part du systme Android, a appelle des fonctions
appeles callbacks.
Exemples :
onCreate Un Intent arrive dans lapplication, il dclenche la cration dune activit, dont linterface.
onPause Le systme prvient lactivit quune autre activit est passe devant, il faut enregistrer les
informations au cas o lutilisateur ne revienne pas.

3.3.4. Squelette dactivit

public class EditActivity extends Activity


{

57
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

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

// met en place les vues de cette activit


setContentView(R.layout.edit_activity);
}
}

@Override signifie que cette mthode remplace celle hrite de la superclasse. Il faut quand mme
lappeler sur super en premier.

3.3.5. Terminaison dune activit


Voici la prise en compte de la terminaison dfinitive dune activit, avec la fermeture dune base de
donnes :
@Override
public void onDestroy() {
super.onDestroy();

// fermer la base
db.close();
}

En fait, il se peut que cette mthode ne soit jamais appele. Voir onStop plutt.

3.3.6. Pause dune activit


Cela arrive quand une nouvelle activit passe devant, exemple : un appel tlphonique. Il faut librer
les ressources qui consomment de lnergie (animations, GPS. . . ).
@Override public void onPause() {
super.onPause();
// arrter les animations sur l'cran
...
}
@Override public void onResume() {
super.onResume();
// dmarrer les animations
...
}

3.3.7. Arrt dune activit


Cela se produit quand lutilisateur change dapplication dans le slecteur dapplications, ou quil
change dactivit dans votre application. Cette activit nest plus visible et doit enregistrer ses
donnes.
Il y a deux mthodes concernes :

58
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

protected void onStop() : lapplication est arrte, librer les ressources,


protected void onStart() : lapplication dmarre, allouer les ressources.
Il faut comprendre que les utilisateurs peuvent changer dapplication tout moment. La votre doit
tre capable de rsister a.

3.3.8. Enregistrement de valeurs dune excution lautre


Il est possible de sauver des informations dun lancement lautre de lapplication (certains cas
comme la rotation de lcran ou une interruption par une autre activit), dans un Bundle. Cest un
container de donnes quelconques, sous forme de couples (nom, valeur).
static final String ETAT_SCORE = "ScoreJoueur"; // nom
private int mScoreJoueur = 0; // valeur

@Override
public void onSaveInstanceState(Bundle etat) {
// enregistrer l'tat courant
etat.putInt(ETAT_SCORE, mScoreJoueur);
super.onSaveInstanceState(etat);
}

3.3.9. Restaurer ltat au lancement


La mthode onRestoreInstanceState reoit un paramtre de type Bundle (comme la mthode
onCreate, mais dans cette dernire, il peut tre null). Il contient ltat prcdemment sauv.
@Override
protected void onRestoreInstanceState(Bundle etat) {
super.onRestoreInstanceState(etat);
// restaurer l'tat prcdent
mScoreJoueur = etat.getInt(ETAT_SCORE);
}

Ces deux mthodes sont appeles automatiquement (sorte dcouteurs), sauf si lutilisateur tue
lapplication. Cela permet de reprendre lactivit l o elle en tait.

3.4. Vues et activits


3.4.1. Obtention des vues
La mthode setContentView charge une disposition sur lcran. Ensuite lactivit peut avoir besoin
daccder aux vues, par exemple lire la chane saisie dans un texte. Pour cela, il faut obtenir lobjet
Java correspondant.
EditText nom = (EditText) findViewById(R.id.edt_nom);

Cette mthode cherche la vue qui possde cet identifiant dans le layout de lactivit. Si cette vue
nexiste pas (mauvais identifiant, ou pas cre), la fonction retourne null.
Un mauvais identifiant peut tre la raison dun bug.

59
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

3.4.2. Proprits des vues


La plupart des vues ont des setters et getters Java pour leurs proprits XML. Par exemple TextView.
En XML :

<TextView android:id="@+id/titre"
android:lines="2"
android:text="@string/debut" />

En Java :

TextView tvTitre = (TextView) findViewById(R.id.titre);


tvTitre.setLines(2);
tvTitre.setText(R.string.debut);

Consulter leur documentation pour les proprits, qui sont extrmement nombreuses.

3.4.3. Actions de lutilisateur


Prenons lexemple de ce Button. Lorsque lutilisateur appuie dessus, cela dclenche un vnement
onClick , et appelle automatiquement la mthode Valider de lactivit.
<Button
android:id="@+id/btn_valider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/valider"
android:onClick="Valider" />

Il faut dfinir la mthode Valider dans lactivit :

public void Valider(View btn) {


...
}

3.4.4. Dfinition dun couteur


Il y a une autre manire de dfinir une rponse un clic : un couteur (listener). Cest une instance
de classe qui possde la mthode public void onClick(View v) ainsi que spcifi par linterface
View.OnClickListener.
Cela peut tre :
une classe prive anonyme,
une classe prive ou public dans lactivit,
lactivit elle-mme.
Dans tous les cas, on fournit cette instance en paramtre la mthode setOnClickListener du
bouton :

60
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

btn.setOnClickListener(ecouteur);

3.4.5. couteur priv anonyme


Il sagit dune classe qui est dfinie la vole, lors de lappel setOnClickListener. Elle ne contient
quune seule mthode.
Button btn = (Button) findViewById(R.id.btn_valider);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View btn) {
// faire quelque chose
}
});

Employer la syntaxe MonActivity.this pour manipuler les variables et mthodes de lactivit


sous-jacente.

3.4.6. couteur priv


Cela consiste dfinir une classe prive dans lactivit ; cette classe implmente linterface
OnClickListener ; et en fournir une instance en tant qucouteur.
private class EcBtnValider implements OnClickListener {
public void onClick(View btn) {
// faire quelque chose
}
};
public void onCreate(...) {
...
Button btn=(Button)findViewById(R.id.btn_valider);
btn.setOnClickListener(new EcBtnValider());
}

3.4.7. Lactivit elle-mme en tant qucouteur


Il suffit de mentionner this comme couteur et dindiquer quelle implmente linterface
OnClickListener.
public class EditActivity extends Activity
implements OnClickListener {
public void onCreate(...) {
...
Button btn=(Button)findViewById(R.id.btn_valider);
btn.setOnClickListener(this);
}
public void onClick(View btn) {
// faire quelque chose
}

Ici, par contre, tous les boutons appelleront la mme mthode.

61
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

3.4.8. Distinction des metteurs


Dans le cas o le mme couteur est employ pour plusieurs vues, il faut les distinguer en se basant
sur leur identitifiant obtenu avec getId() :

public void onClick(View v) {


switch (v.getId()) {
case R.id.btn_valider:
...
break;
case R.id.btn_effacer:
...
break;
}
}

3.4.9. vnements des vues courantes


Vous devrez tudier la documentation. Voici quelques exemples :
Button : onClick lorsquon appuie sur le bouton, voir sa doc
Spinner : OnItemSelected quand on choisit un lment, voir sa doc
RatingBar : OnRatingBarChange quand on modifie la note, voir sa doc
etc.
Heureusement, dans le cas de formulaires, les actions sont majoritairement bases sur des boutons.

3.4.10. Cest fini pour aujourdhui


Cest assez pour cette semaine, rendez-vous la semaine prochaine pour un cours sur les applications
de gestion de donnes (listes ditems).
Plus tard, nous verrons comment Android raffine la notion dactivit, en la sparant en fragments.

62
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Semaine 4

Application liste

Durant les prochaines semaines, nous allons nous intresser aux applications de gestion dune liste
ditems.
Stockage dune liste
Affichage dune liste, adaptateurs
Consultation et dition dun item

Figure 22: Liste ditems

4.1. Prsentation
4.1.1. Principe gnral
On veut programmer une application pour afficher et diter une liste ditems.
Cette semaine, la liste est stocke dans un tableau dynamique appel ArrayList ; en semaine
6, a sera dans une base de donnes SQL locale ou sur un serveur distant.

63
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Lcran est occup par un ListView. Cest une vue spcialise dans laffichage de listes
quelconques.
Consulter cette documentation sur les ListView.

4.1.2. Schma global


Lintermdiaire entre la liste et la vue est gr par un adaptateur, objet qui sait comment afficher un
item dans le ListView.

Figure 23: Vue, adaptateur et donnes

4.1.3. Une classe pour reprsenter les items


Pour commencer, une classe pour reprsenter les items :

public class Planete {


public String mNom;
public int mDistance;

Planete(String nom, int distance) {


mNom = nom; // nom de la plante
mDistance = distance; // distance au soleil en Gm
}

public String toString() {


return mNom;
}
};

4.1.4. Donnes initiales


Deux solutions pour initialiser la liste avec des items prdfinis :
Un tableau dans les ressources, voir page 65,

64
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Un tableau Java comme ceci :

final Planete[] initdata = {


new Planete("Mercure", 58),
new Planete("Vnus", 108),
new Planete("Terre", 150),
...
};

final signifie constant, sa valeur ne changera plus.

4.1.5. Copie dans un ArrayList


Ltape suivante consiste recopier les valeurs initiales dans un tableau dynamique de type
ArrayList<Planete> :

protected ArrayList<Planete> mliste;

void onCreate(...)
{
...
// cration du tableau dynamique
mListe = new ArrayList<Planete>();
// boucle amliore Java7
for (Planete planete: initdata) {
mListe.add(planete);
}
}

4.1.6. Le container Java ArrayList<type>


Cest un type de donnes gnrique, cest dire paramtr par le type des lments mis entre <. . . > ;
ce type doit tre un objet.

import java.util.ArrayList;
ArrayList<TYPE> liste = new ArrayList<TYPE>();

Quelques mthodes utiles :


liste.size() : retourne le nombre dlments prsents,
liste.clear() : supprime tous les lments,
liste.add(elem) : ajoute cet lment la liste,
liste.remove(elem ou indice) : retire cet lment
liste.get(indice) : retourne llment prsent cet indice,
liste.contains(elem) : true si elle contient cet lment,
liste.indexOf(elem) : indice de llment, sil y est.

65
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

4.1.7. Donnes initiales dans les ressources


On cre deux tableaux dans le fichier res/values/arrays.xml :

<resources>
<string-array name="noms">
<item>Mercure</item>
<item>Venus</item>
...
</string-array>
<integer-array name="distances">
<item>58</item>
<item>108</item>
...
</integer-array>
</resources>

4.1.8. Donnes dans les ressources, suite


Ensuite, on rcupre ces tableaux pour remplir le ArrayList :

// accs aux ressources


Resources res = getResources();
final String[] noms = res.getStringArray(R.array.noms);
final int[] distances = res.getIntArray(R.array.distances);

// recopie dans le ArrayList


mListe = new ArrayList<Planete>();
for (int i=0; i<noms.length; ++i) {
mListe.add(new Planete(noms[i], distances[i]));
}

4.1.9. Remarques
Cette semaine, les donnes sont reprsentes dans un tableau. Dans les exemples prcdents, cest une
variable membre de lactivit. Pour faire mieux que cela, il faut dfinir une Application comme en
semaine 3 et mettre ce tableau ainsi que son initialisation dedans. Ainsi, le tableau devient disponible
dans toutes les activits de lapplication. Voir le TP4.
En semaine 6, nous verrons comment utiliser une base de donnes SQL locale ou un WebService, ce
qui rsoud proprement le problme.

4.2. Affichage de la liste


4.2.1. Activit spcialise ou layout
Deux possibilits :
employer la classe ListActivity,

66
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

employer la classe Activity de base.


Ces deux possibilits sont trs similaires : un layout contenant un ListView pour lactivit, un layout
pour les items de la liste et un adaptateur pour accder aux donnes.
La ListActivity prpare un peu plus de choses pour grer les slections ditems, tandis quavec une
simple Activity, cest nous de tout faire, voir page 74. Par exemple, si on rajoute un TextView
particulier, on peut avoir un message La liste est vide .

4.2.2. Mise en uvre


Que ce soit avec une ListActivity ou avec une Activity de base, deux choses sont faire :
1. Crer un layout pour lcran ; il doit contenir un ListView identifi par @android:id/list,
2. Crer un layout pour un item ; il doit contenir un TextView identifi par @android:id/text1,
Consulter la documentation.

4.2.3. Layout de lactivit pour afficher une liste


Voici dabord le layout dcran. Jai rajout le TextView qui affiche Liste vide . Notez les identifiants
spciaux.

<LinearLayout xmlns:android="..."
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView android:id="@android:id/empty"
android:text="Liste vide"
... />
</LinearLayout>

On peut rajouter dautres vues : boutons. . .

4.2.4. Mise en place du layout dactivit


Classiquement :

@Override
protected void onCreate(Bundle savedInstanceState)
{
// appeler la mthode surcharge dans la superclasse
super.onCreate(savedInstanceState);

// mettre en place le layout contenant le ListView


setContentView(R.layout.main);

67
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

// initialisation de la liste
mListe = new ArrayList<Planete>();
...

4.2.5. Layout pour un item


Ensuite, le layout res/layout/item.xml pour afficher un item. Lidentifiant du TextView devient
android.R.id.text1 en Java.
<LinearLayout xmlns:android="..."
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="@android:id/text1"
android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

4.2.6. Autre layouts


Il est possible de crer des dispositions plus complexes pour les items mais alors il faudra programmer
un adaptateur spcifique.

Figure 24: Layout complexe

<RelativeLayout xmlns:android="..." ...>


<ImageView android:id="@+id/item_planete_image" .../>
<TextView android:id="@+id/item_planete_nom" .../>
<TextView android:id="@+id/item_planete_distance" .../>
</RelativeLayout>

Voir les adaptateurs personnaliss, page 70.

4.2.7. Layouts prdfinis


Android dfinit des layouts pour des lments de listes simples :
android.R.layout.simple_list_item_1
Cest un layout qui affiche un seul TextView. Son identifiant est android.R.id.text1,
android.R.layout.simple_list_item_2
Cest un layout qui affiche deux TextView : un titre en grand et un sous-titre. Ses identifiants
sont android.R.id.text1 et android.R.id.text2.
Il suffit de les fournir ladaptateur. Il ny a pas besoin de crer des fichiers XML, ni pour lcran, ni
pour les items.

68
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

4.3. Adaptateurs
4.3.1. Relations entre la vue et les donnes
Un ListView affiche les items laide dun adaptateur (adapter).

Figure 25: Adaptateur entre les donnes et la vue

4.3.2. Rle dun adaptateur


Ladaptateur rpond la question que pose le ListView : que dois-je afficher tel endroit dans la
liste ? . Il va chercher les donnes et instancie le layout ditem avec les valeurs.
Cest une classe qui :
accde aux donnes laide de mthodes telles que getItem(int position), getCount(),
isEmpty() quelque soit le type de stockage des lments : tableau, BDD. . .
cre les vues daffichage des items : getView(...) laide du layout des items. Cela consiste
instancier le layout on dit expanser le layout, inflate en anglais.

4.3.3. Adaptateurs prdfinis


Android propose quelques classes dadaptateurs prdfinis, dont :
ArrayAdapter pour un tableau simple (liste dynamique),
SimpleCursorAdapter pour accder une base de donnes, quon verra dans deux semaines.
En gnral, dans une application innovante, il faut dfinir son propre adaptateur, voir page 70, mais
commenons par un ArrayAdapter standard.

4.3.4. ArrayAdapter<Type> pour les listes


Il permet dafficher les donnes dun ArrayList, mais il est limit une seule chane par item, par
exemple le nom dune plante, fournie par sa mthode toString(). Son constructeur :
ArrayAdapter(Context context, int item_layout_id, int textview_id, List<T> donnes)

69
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

context cest lactivit qui cre cet adaptateur, mettre this


item_layout_id identifiant du layout des items, p. ex. android.R.layout.simple_list_item_1
ou R.layout.item_planete
textview_id identifiant du TextView dans ce layout, p. ex. android.R.id.text1 ou
R.id.item_planete_nom
donnes cest la liste contenant les donnes (List est une surclasse de ArrayList)

4.3.5. Exemple demploi


Suite de la mthode onCreate de lactivit, on fournit la ArrayList<Planete> mListe au construc-
teur dadaptateur :

// crer un adaptateur standard pour mListe


ArrayAdapter<Planete> adapter =
new ArrayAdapter<Planete>(this,
R.layout.item_planete,
R.id.item_planete_nom,
mListe);
// associer la liste affiche et l'adaptateur
ListView lv = (ListView) findViewById(android.R.id.list);
lv.setAdapter(adapter);

La classe Planete doit avoir une mthode toString(), cf page 63. Cet adaptateur naffiche que le
nom de la plante, rien dautre.

4.3.6. Affichage avec une ListActivity


Si lactivit est une ListActivity, la fin est peu plus simple :

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

mListe = new ArrayList<Planete>();


...

ArrayAdapter<Planete> adapter = new ArrayAdapter...

// association liste - adaptateur


setListAdapter(adapter);
}

4.3.7. Exemple avec les layouts standards


Avec les layouts ditems standards Android, cela donne :

70
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

// crer un adaptateur standard pour mListe


ArrayAdapter<Planete> adapter =
new ArrayAdapter<Planete>(this,
android.R.layout.simple_list_item_1,
android.R.id.text1,
mListe);

// associer la liste affiche et l'adaptateur


setListAdapter(adapter);

Le style daffichage est minimaliste, seulement la liste des noms. On ne peut pas afficher deux
informations avec un ArrayAdapter.

4.4. Adaptateur personnalis


4.4.1. Classe Adapter personnalise
Parce que ArrayAdapter naffiche quun seul texte, nous allons dfinir notre propre adaptateur :
PlaneteAdapter.
Il faut le faire hriter de ArrayAdapter<Planete> pour ne pas tout reprogrammer :

public class PlaneteAdapter extends ArrayAdapter<Planete>


{
public PlaneteAdapter(Context context,
List<Planete> planetes)
{
super(context, 0, planetes);
}

Source biblio : http://www.bignerdranch.com/blog/customizing-android-listview-rows-subclassing

4.4.2. Classe Adapter perso, suite


Sa principale mthode est getView qui cre les vues pour le ListView. Elle retourne une disposition,
p. ex. un RelativeLayout contenant des TextView et ImageView.

public
View getView(int position, View recup, ViewGroup parent);

position est le numro, dans le ListView, de litem afficher.


recup est une ancienne vue devenue invisible dans le ListView. Cest une technique pour
diminuer les allocations mmoire, on rcupre une vue inutile au lieu den allouer une nouvelle.
NB: elle sappelle convertView dans les docs.
parent : le ListView auquel sera rattach cette vue.

71
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

4.4.3. Mthode getView personnalise


Voici la surcharge de cette mthode :

@Override
public View
getView(int position, View recup, ViewGroup parent)
{
// crer ou rcuprer un PlaneteView
PlaneteView vueItem = (PlaneteView) recup;
if (vueItem == null)
vueItem = PlaneteView.create(parent); // <==(!!)

// afficher les valeurs


vueItem.display(super.getItem(position));
return vueItem;
}

4.4.4. Mthode PlaneteView.create


Cette mthode cre une instance de PlaneteView. Cest un groupe de vues qui affiche un seul item
des donnes.
Le PlaneteAdapter cre des PlaneteView la demande du ListView,
Un PlaneteView est une sorte de RelativeLayout contenant des TextView et ImageView

Figure 26:

Cette disposition est dfinie par un fichier layout XML res/layout/item_planete.xml.


Lensemble des donnes est affich par plusieurs instances de PlaneteView dans le ListView.

4.4.5. Layout ditem res/layout/item_planete.xml


Cest subtil : on va remplacer la racine du layout des items, un RelativeLayout par une classe
personnalise :

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


<fr.iutlan.planetes.PlaneteView
xmlns:android="..."
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

Et cette classe PlaneteView hrite de RelativeLayout :

72
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

package fr.iutlan.planetes;
public class PlaneteView extends RelativeLayout
{
...

4.4.6. Classe personnalise dans les ressources


Android permet dutiliser les classes de notre application lintrieur dun layout. Il suffit de les
prfixer par le package.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="..."
android:layout_width="match_parent"
android:layout_height="wrap_content">
<fr.iutlan.customviews.MaVuePerso
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

La classe MaVuePerso doit hriter de View et implmenter certaines mthodes.

4.4.7. Classe PlaneteView pour afficher les items


Cette classe a pour but de grer les vues dans lesquelles il y a les informations des plantes : nom,
distance, image.
On la met la place du RelativeLayout dans res/layout/item_planete.xml :
<?xml version="1.0" encoding="utf-8"?>
<fr.iutlan.planetes.PlaneteView .../>
<ImageView android:id="@+id/item_planete_image" .../>
<TextView android:id="@+id/item_planete_nom" .../>
<TextView android:id="@+id/item_planete_distance" .../>
</fr.iutlan.planetes.PlaneteView>

Les proprits de placement restent les mmes.

4.4.8. Dfinition de la classe PlaneteView


Le constructeur de PlaneteView est ncessaire, mais quasi-vide :
public class PlaneteView extends RelativeLayout
{
public PlaneteView(Context context, ...) {
super(context, attrs);
}

Tout se passe dans la mthode de classe PlaneteView.create appele par ladaptateur. Rappel de
la page 71 :

73
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

// crer ou rcuprer un PlaneteView


PlaneteView vueItem = (PlaneteView) recup;
if (vueItem == null) vueItem = PlaneteView.create(parent);
...

Cette mthode create gnre les vues du layout item.xml.

4.4.9. Crer des vues partir dun layout XML


La gnration de vues pour afficher les items repose sur un mcanisme appel LayoutInflater qui
fabrique des vues Android partir dun layout XML :

LayoutInflater li = LayoutInflater.from(context);
View vueItem = li.inflate(R.layout.item_planete, parent);

On lui fournit lidentifiant du layout, p. ex. celui des items. Elle cre les vues spcifies dans
res/layout/item_planete.xml.
context est lactivit qui affiche toutes ces vues,
parent est la vue qui doit contenir ces vues, null si aucune.

4.4.10. Mthode PlaneteView.create


La mthode de classe PlaneteView.create expanse le layout des items laide dun LayoutInflater :

public static PlaneteView create(ViewGroup parent)


{
LayoutInflater li =
LayoutInflater.from(parent.getContext());
PlaneteView itemView = (PlaneteView)
li.inflate(R.layout.item_planete, parent, false);
itemView.findViews();
return itemView;
}

static signifie quon appelle cette mthode sur la classe elle-mme et non pas sur une instance. Cest
une mthode de classe.

4.4.11. Mthode findViews


Cette mthode a pour but de rcuprer les objets Java des TextView et ImageView de litem. Elle les
recherche avec leurs proprits android:id.

private void findViews()


{
tvNom = (TextView) findViewById(R.id.item_planete_nom);
tvDistance = (TextView)

74
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

findViewById(R.id.item_planete_distance);
ivImage = (ImageView)
findViewById(R.id.item_planete_image);
}

Ces trois variables sont des membres dinstance du PlaneteView.

4.4.12. Pour finir, la mthode PlaneteView.display


Son rle est dafficher les informations dune plante dans les TextView et ImageView de litem.

public void display(final Planete planete)


{
tvNom.setText(planete.getNom());
tvDistance.setText(
Integer.toString(planete.getDistance())
+ " millions de km");
ivImage.setImageResource(planete.getIdImage());
}

Elle utilise les getters de la classe Planete : getNom. . .

4.4.13. Rcapitulatif
Voici la squence qui amne laffichage dun item dans la liste :
1. Le ListView appelle la mthode getView(position, ...) de ladaptateur, position est le
no de llment concern,
2. Ladaptateur appelle ventuellement PlaneteView.create :
a. PlaneteView.create fait instancier item.xml = une sous-classe de RelativeLayout
appele PlaneteView.
b. Cela cre les vues nom, distance et image dont PlaneteView.findViews rcupre les
objets Java.
3. Ladaptateur appelle la mthode display du PlaneteView avec les donnes afficher.
a. PlaneteView.display appelle setText des vues pour afficher les valeurs.

4.4.14. Le rsultat

4.5. Actions utilisateur sur la liste


4.5.1. Modification des donnes
Les modifications sur les donnes doivent se faire par les mthodes add, insert, remove et clear de
ladaptateur. Voir la doc.
Si ce nest pas possible, par exemple parce quon a chang dactivit et modifi les donnes sans
adaptateur, alors au retour, par exemple dans onActivityResult, il faut prvenir ladaptateur par
la mthode suivante :

75
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 27: Liste ditems

adapter.notifyDataSetChanged();

4.5.2. Clic sur un lment


Voyons le traitement des slections utilisateur sur une liste. La classe ListActivity dfinit dj un
couteur pour les clics. Il suffit de le surcharger :

@Override
public void onListItemClick (
ListView l, View v, int position, long id)
{
// grer un clic sur l'item identifi par id
...
}

Par exemple, crer un Intent pour afficher ou diter litem. Ne pas oublier dappeler
adapter.notifyDataSetChanged(); au retour.

4.5.3. Clic sur un lment, suite


Si votre activit est une simple Activity (parce quil y a autre chose quune liste, ou plusieurs listes),
alors cest plus complexe :
Votre activit doit implmenter linterface AdapterView.OnItemClickListener,

76
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Vous devez dfinir this en tant qucouteur du ListView,


Votre activit doit surcharger la mthode onItemClick.

4.5.4. Clic sur un lment, suite

public class MainActivity extends Activity


implements OnItemClickListener
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
// appeler la mthode surcharge dans la superclasse
super.onCreate(savedInstanceState);

// mettre en place le layout contenant le ListView


setContentView(R.layout.main);
ListView lv=(ListView)findViewById(android.R.id.list);
lv.setOnItemClickListener(this);
}

4.5.5. Clic sur un lment, fin


Et voici sa mthode onItemClick :

@Override
public void onItemClick(
AdapterView<?> parent, View v, int position, long id)
{
// grer un clic sur l'item identifi par id
...
}

Il existe aussi la mthode boolean onItemLongClick ayant les mmes paramtres, installe par
setOnItemLongClickListener.

4.5.6. Liste dlments cochables


Android offre des listes cochables comme celles-ci :
Le style de la case cocher dpend du choix unique ou multiple.

4.5.7. Liste cochable simple


Android propose un layout prdfini pour items cochables :

77
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 28: lments cochables

@Override
protected void onCreate(Bundle savedInstanceState)
{
...
setListAdapter(
new ArrayAdapter<Planete>(this
android.R.layout.simple_list_item_checked,
android.R.id.text1, mListe));

ListView lv=(ListView)findViewById(android.R.id.list);
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}

4.5.8. Liste choix multiples


Toujours avec des listes prdfinies, cest une simple variante :
mettre simple_list_item_multiple_choice la place de simple_list_item_checked,
mettre ListView.CHOICE_MODE_MULTIPLE au lieu de ListView.CHOICE_MODE_SINGLE.
La mthode onListItemClick est appele sur chaque lment cliqu.

4.5.9. Liste cochable personnalise


Si on veut un layout personnalis comme PlaneteView, il faut que sa classe implmente linterface
Checkable cd 3 mthodes :
public boolean isChecked() indique si litem est coch
public void setChecked(boolean etat) doit changer ltat interne de litem
public void toggle() doit inverser ltat interne de litem
Il faut rajouter un boolen dans chaque item, celui que jai appel tat interne.
Dautre part, dans le layout ditem, il faut employer un CheckedTextView mme vide, plutt quun
CheckBox qui ne ragit pas aux clics (bug Android).

78
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

4.5.10. Ouf, cest fini


Cest tout pour cette semaine. La semaine prochaine nous parlerons des menus, dialogues et fragments.

79
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Semaine 5

Ergonomie

Le cours de cette semaine concerne lergonomie dune application Android.


Menus et barre daction
Popup-up : messages et dialogues
Activits et fragments
Prfrences (pour info)
Bibliothque support (pour info)

5.1. Barre daction et menus


5.1.1. Barre daction
La barre daction contient licne dapplication (1), quelques items de menu (2) et un bouton pour
avoir les autres menus (3).

Figure 29: Barre daction

5.1.2. Ralisation dun menu


Avant Android 3.0 (API 11), les actions dune application taient lances avec un bouton de menu,
mcanique. Depuis, elles sont dclenches par la barre daction. Cest presque la mme chose.
Le principe gnral : un menu est une liste ditems qui apparat soit quand on appuie sur le bouton
menu, soit sur la barre daction. Certains de ces items sont prsents en permanence dans la barre
daction. La slection dun item dclenche une callback.
Docs Android sur la barre daction et sur les menus
Il faut dfinir :
un fichier res/menu/nom_du_menu.xml,

80
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

des thmes pour afficher soit la barre daction, soit des menus,
deux callbacks pour grer les menus : cration et activation.

5.1.3. Spcification dun menu


Crer res/menu/nom_du_menu.xml :

<menu xmlns:android="..." >


<item android:id="@+id/menu_creer"
android:icon="@drawable/ic_menu_creer"
android:showAsAction="ifRoom"
android:title="@string/menu_creer"/>
<item android:id="@+id/menu_chercher" ... />
...
</menu>

Chaque <item> : identifiant, icne et titre, ainsi que lattribut showAsAction valant "always",
"ifRoom" ou "never" selon la visibilit quon souhaite dans la barre daction.

5.1.4. Icnes pour les menus


Android distribue gratuitement un grand jeu dicnes pour les menus, dans les deux styles : HoloDark
et HoloLight.

Figure 30: Icnes de menus

Consulter la page Downloads pour des tlchargements gratuits de toutes sortes de modles et feuilles
de styles.
Tlchargez Action Bar Icon Pack pour amliorer vos applications.

5.1.5. Thme pour une barre daction


Les thmes permettent dafficher soit une barre daction, soit un menu ancien style. Ils sont dfinis
dans trois dossiers :
res\values\styles.xml
res\values-v11\styles.xml
res\values-v14\styles.xml
En rsum, il faut indiquer que votre application gre les barres daction. Voici par exemple pour la
V11 :

81
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

<resources>
<style name="AppBaseTheme"
parent="android:Theme.Holo.Light" />
</resources>

Utiliser lassistant pour avoir les thmes adquats.

5.1.6. couteurs pour les menus


Il faut programmer deux mthodes. Lune affiche le menu, lautre ragit quand lutilisateur slectionne
un item. Voici la premire :

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.nom_du_menu, menu);
return true;
}

Cette mthode rajoute les items du menu dfini dans le XML.


Un MenuInflater est un lecteur/traducteur de fichier XML en vues ; sa mthode inflate cre les
vues.

5.1.7. Ractions aux slections ditems


Voici la seconde callback, cest un aiguillage selon litem choisi :

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_creer:
...
return true;
case R.id.menu_chercher:
...
return true;
...
default: return super.onOptionsItemSelected(item);
}
}

5.1.8. Menus en cascade


Dfinir deux niveaux quand la barre daction est trop petite :

82
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

<menu xmlns:android="..." >


<item android:id="@+id/menu_item1" ... />
<item android:id="@+id/menu_item2" ... />
<item android:id="@+id/menu_more"
android:icon="@drawable/ic_action_overflow"
android:showAsAction="always"
android:title="@string/menu_more">
<menu>
<item android:id="@+id/menu_item3" ... />
<item android:id="@+id/menu_item4" ... />
</menu>
</item>
</menu>

5.1.9. Menus contextuels

Figure 31: MenuContextuel

Ces menus apparaissent lors un clic long sur un lment de liste. Le principe est le mme que pour
les menus normaux :
Attribuer un couteur lvnement onCreateContextMenu. Cet vnement correspond un
clic long et au lieu dappeler la callback du clic long, a fait apparatre le menu.
Dfinir la callback de lcouteur : elle expanse un layout de menu.
Dfinir la callback des items du menu.

5.1.10. Associer un menu contextuel une vue


Cela se passe par exemple dans la mthode onCreate dune activit :

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView lv = (ListView)findViewById(android.R.id.list);
registerForContextMenu(lv);
...

Au lieu de registerForContextMenu(lv); on peut aussi faire :

83
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

lv.setOnCreateContextMenuListener(this);

5.1.11. Callback daffichage du menu


Quand lutilisateur fait un clic long, cela dclenche cette mthode :
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.main_context, menu);
}

Son rle est dexpanser (inflate) le menu res/menu/main_context.

5.1.12. Callback des items du menu


Pour finir, si lutilisateur choisit un item du menu :
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (ACMI...) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.editer:
onMenuEditer(info.id); // identifiant de l'lment
return true;
case R.id.supprimer:
onMenuSupprimer(info.id);
return true;
}
return false;
}

Lobjet AdapterContextMenuInfo info permet davoir lidentifiant de ce qui est slectionn, qui a
fait apparatre le menu contextuel.

5.2. Annonces et dialogues


5.2.1. Annonces : toasts
Un toast est un message apparaissant en bas dcran pendant un instant, par exemple pour
confirmer la ralisation dune action. Un toast naffiche aucun bouton et nest pas actif.
Voici comment lafficher avec une ressource chane :
Toast.makeText(getApplicationContext(),
R.string.item_supprime, Toast.LENGTH_SHORT).show();

La dure daffichage peut tre allonge avec LENGTH_LONG.

84
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 32: Toast

5.2.2. Annonces personnalises


Il est possible de personnaliser une annonce. Il faut seulement dfinir un layout dans
res/layout/toast_perso.xml. La racine de ce layout doit avoir un identifiant, ex : toast_perso_id
qui est mentionn dans la cration :

// expanser le layout du toast


LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast_perso,
(ViewGroup) findViewById(R.id.toast_perso_id));
// crer le toast et l'afficher
Toast toast = new Toast(getApplicationContext());
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(layout);
toast.show();

5.2.3. Dialogues
Un dialogue est une petite fentre qui apparat au dessus dun cran pour afficher ou demander
quelque chose durgent lutilisateur, par exemple une confirmation.

Figure 33: Dialogue dalerte

Il existe plusieurs sortes de dialogues :


Dialogues dalerte
Dialogues gnraux

5.2.4. Dialogue dalerte


Un dialogue dalerte AlertDialog affiche un texte et un trois boutons au choix : ok, annuler, oui,
non, aide. . .
Un dialogue dalerte est construit laide dune classe nomme AlertDialog.Builder. Le principe
est de crer un builder et cest lui qui cre le dialogue. Voici le dbut :

85
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Builder confirm = new AlertDialog.Builder(this);


confirm.setTitle("Suppression");
confirm.setIcon(android.R.drawable.ic_dialog_alert);
confirm.setMessage("Vous confirmez la suppression ?");

Ensuite, on rajoute les boutons et leurs couteurs.

5.2.5. Boutons et affichage dun dialogue dalerte


Le builder permet de rajouter toutes sortes de boutons : oui/non, ok/annuler. . . Cela se fait avec des
fonctions comme celle-ci. On peut associer un couteur (anonyme priv ou . . . ) ou aucun.

// rajouter un bouton "oui" qui supprime vraiment


confirm.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int idBtn) {
SupprimerElement(idElement);
}
});
// rajouter un bouton "non" qui ne fait rien
confirm.setNegativeButton(android.R.string.no, null);
// affichage du dialogue
confirm.show();

5.2.6. Autres types de dialogues dalerte


Dans un dialogue dalerte, au lieu de boutons, il est possible dafficher une liste de propositions
prdfinies. Pour cela :
Dfinir une ressource de type tableau de chanes res/values/arrays.xml :

<resources>
<string-array name="notes">
<item>Nul</item>
<item>a le fait</item>
<item>Trop cool</item>
</string-array>
</resources>

Appeler la mthode confirm.setItems(R.array.notes, couteur). Lcouteur est le mme


que pour un clic. Il reoit le numro du choix en 2e paramtre idBtn.
Dans ce cas, ne pas appeler confirm.setMessage car ils sont exclusifs. Cest soit une liste, soit un
message.

5.2.7. Dialogues personnaliss


Lorsquil faut demander une information plus complexe lutilisateur, mais sans que a ncessite une
activit part entire, il faut faire appel un dialogue personnalis.

86
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 34: Dialogue perso

5.2.8. Cration dun dialogue


Il faut dfinir le layout du dialogue incluant tous les textes, sauf le titre, et au moins un bouton pour
valider, sachant quon peut fermer le dialogue avec le bouton back.

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


<LinearLayout xmlns:android="..." ...>
<TextView android:id="@+id/dialog_titre" .../>
<EditText android:id="@+id/dialog_libelle" .../>
<Button android:id="@+id/dialog_btn_valider" ... />
</LinearLayout>

Ensuite cela ressemble ce quon fait dans onCreate dune activit : setContentView avec le layout
et des setOnClickListener pour attribuer une action aux boutons.

5.2.9. Affichage du dialogue

// crer le dialogue
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.edit_dialog);
dialog.setTitle("Cration d'un type");
// bouton valider
Button btnValider =
(Button) dialog.findViewById(R.id.dialog_btn_valider);
btnValider.setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) {
... // rcuprer et traiter les infos
dialog.dismiss(); // fermer le dialogue
}
});
// afficher le dialogue
dialog.show();

87
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

5.3. Fragments et activits


5.3.1. Fragments
Depuis Android 4, les dialogues doivent tre grs par des instances de DialogFragment qui sont
des sortes de fragments, voir cette page. Cela va plus loin que les dialogues. Toutes les parties des
interfaces dune application sont susceptibles de devenir des fragments :
liste ditems
affichage des infos dun item
dition dun item
Un fragment est une sorte de mini-activit. Dans le cas dun dialogue, elle gre laffichage et la vie du
dialogue. Dans le cas dune liste, elle gre laffichage et les slections des lments.

5.3.2. Tablettes, smartphones. . .


Une interface devient plus souple avec des fragments. Selon la taille dcran, on peut afficher une liste
et les dtails, ou sparer les deux.

Figure 35: Diffrentes apparences

5.3.3. Structure dun fragment


Un fragment est une activit trs simplifie. Cest seulement un arbre de vue dfini par un layout, et
des couteurs. Un fragment minimal est :

88
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

public class InfosFragment extends Fragment


{
public InfosFragment() {}

@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(
R.layout.infos_fragment, container, false);
}
}

5.3.4. Diffrents types de fragments


Il existe diffrents types de fragments, voici quelques uns :
ListFragment pour afficher une liste ditems, comme le ferait une ListActivity.
DialogFragment pour afficher un fragment dans une fentre flottante au dessus dune activit.
PreferenceFragment pour grer les prfrences.
En commun : il faut surcharger la mthode onCreateView qui dfinit leur contenu.

5.3.5. Cycle de vie des fragments


Les fragments ont un cycle de vie similaire celui des activits, avec quelques mthodes de plus
correspondant leur intgration dans une activit.

Figure 36: Cycle de vie dun fragment

5.3.6. ListFragment
Par exemple, voici lattribution dun layout standard pour la liste :

89
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState)
{
// liste des lments venant de l'application
FragmentApplication app = (FragmentApplication)
getActivity().getApplicationContext();
listeItems = app.getListe();

// layout du fragment
setHasOptionsMenu(true); // le fragment a un menu
return inflater.inflate(android.R.layout.list_content,
container, false);
}

5.3.7. ListFragment, suite


Voici la suite, le remplissage de la liste et lattribution dun couteur pour les clics sur les lments :

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
// adaptateur standard pour la liste
ArrayAdapter<Item> adapter = new ArrayAdapter<Item>(
getActivity(), android.R.layout.simple_list_item_1,
listeItems);
setListAdapter(adapter);
// attribuer un couteur pour les clics sur les items
ListView lv = getListView();
lv.setOnItemClickListener(this);
}

5.3.8. Menus de fragments


Un fragment peut dfinir un menu. Ses lments sont intgrs la barre daction de lactivit. Seule
la mthode de cration du menu diffre, linflater arrive en paramtre :
@Override
public void onCreateOptionsMenu(
Menu menu, MenuInflater menuInflater)
{
super.onCreateOptionsMenu(menu, menuInflater);
menuInflater.inflate(R.menu.edit_fragment, menu);
}

NB: dans la mthode onCreateView du fragment, il faut rajouter setHasOptionsMenu(true);

90
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

5.3.9. Intgrer un fragment dans une activit


De lui-mme, un fragment nest pas capable de safficher. Il ne peut apparatre que dans le cadre
dune activit, comme une sorte de vue interne. On peut le faire de deux manires :
statiquement : les fragments afficher sont prvus dans le layout de lactivit. Cest le plus
simple faire et comprendre.
dynamiquement : les fragments sont ajouts, enlevs ou remplacs en cours de route selon les
besoins.

5.3.10. Fragments statiques dans une activit


Dans ce cas, cest le layout de lactivit qui inclut les fragments, p. ex. res/layout-land/main_activity.xml.
Ils ne peuvent pas tre modifis ultrieurement.

<LinearLayout ... android:orientation="horizontal" ... >


<fragment
android:id="@+id/frag_liste"
android:name="fr.iutlan.fragments.ListeFragment"
... />
<fragment
android:id="@+id/frag_infos"
android:name="fr.iutlan.fragments.InfosFragment"
... />
</LinearLayout>

Chaque fragment doit avoir un identifiant et un nom complet.

5.3.11. FragmentManager
Pour dfinir des fragments dynamiquement, on fait appel au FragmentManager de lactivit. Il gre
laffichage des fragments. Lajout et la suppression de fragments se fait laide de transactions. Cest
simplement lassociation entre un rceptacle (un FrameLayout vide) et un fragment.
Soit un layout contenant deux FrameLayout vides :

<LinearLayout xmlns:android="..."
android:orientation="horizontal" ... >
<FrameLayout android:id="@+id/frag_liste" ... />
<FrameLayout android:id="@+id/frag_infos" ... />
</LinearLayout>

On peut dynamiquement attribuer un fragment chacun.

5.3.12. Attribution dun fragment dynamiquement


En trois temps : obtention du manager, cration dune transaction et attribution des fragments aux
rceptacles .

91
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

// gestionnaire
FragmentManager manager = getFragmentManager();

// transaction
FragmentTransaction trans = manager.beginTransaction();

// mettre les fragments dans les rceptacles


trans.add(R.id.frag_liste, new ListeFragment());
trans.add(R.id.frag_infos, new InfosFragment());
trans.commit();

Les FrameLayout sont remplacs par les fragments.

5.3.13. Disposition selon la gomtrie de lcran


Le plus intressant est de faire apparatre les fragments en fonction de la taille et lorientation de
lcran (application liste + infos ).

Figure 37: Un ou deux fragments affichs

5.3.14. Changer la disposition selon la gomtrie


Pour cela, il suffit de dfinir deux layouts (dfinition statique) :
res/layout-port/main_activity.xml en portrait :

<LinearLayout xmlns:android="..."
android:orientation="horizontal" ... >
<fragment android:id="@+id/frag_liste" ... />
</LinearLayout>

res/layout-land/main_activity.xml en paysage :

92
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

<LinearLayout xmlns:android="..."
android:orientation="horizontal" ... >
<fragment android:id="@+id/frag_liste" ... />
<fragment android:id="@+id/frag_infos" ... />
</LinearLayout>

5.3.15. Deux dispositions possibles


Lorsque la tablette est verticale, le layout de layout-port est affich et lorsquelle est horizontale,
cest celui de layout-land.
Lactivit peut alors faire un test pour savoir si le fragment frag_infos est affich :

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
FragmentManager manager = getFragmentManager();
InfosFragment frag_infos = (InfosFragment)
manager.findFragmentById(R.id.frag_infos);
if (frag_infos != null) {
// le fragment des informations est prsent
...
}

5.3.16. Communication entre Activit et Fragments


Lorsque lutilisateur clique sur un lment de la liste du fragment frag_liste, cela doit afficher ses
informations :
dans le fragment frag_infos sil est prsent,
ou lancer une activit daffichage spare si le fragment nest pas prsent (layout vertical).
Cela implique plusieurs petites choses :
Lcouteur des clics sur la liste est le fragment frag_liste. Il doit transmettre litem cliqu
lactivit.
Lactivit doit dterminer si le fragment frag_infos est affich :
sil est visible, elle lui transmet litem cliqu
sinon, elle lance une activit spcifique, InfosActivity.
Voici les tapes.

5.3.17. Interface pour un couteur


Dabord la classe ListeFragment : dfinir une interface pour grer les slections ditems et un
couteur :

93
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

public interface OnItemSelectedListener {


public void onItemSelected(Item item);
}

private OnItemSelectedListener listener;

Ce sera lactivit principale qui sera cet couteur, grce :

@Override public void onAttach(Activity activity)


{
super.onAttach(activity);
listener = (OnItemSelectedListener) activity;
}

5.3.18. couteur du fragment


Toujours dans la classe ListeFragment, voici la callback pour les slections dans la liste :

@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id)
{
Item item = listeItems.get((int)id);
listener.onItemSelected(item);
}

Elle va chercher litem slectionn et le fournit lcouteur, cest dire lactivit principale.

5.3.19. couteur de lactivit


Voici maintenant lcouteur de lactivit principale :

@Override public void onItemSelected(Item item)


{
FragmentManager manager = getFragmentManager();
InfosFragment frag_infos = (InfosFragment)
manager.findFragmentById(R.id.frag_infos);
if (frgInfos != null && frgInfos.isVisible()) {
// le fragment est prsent, alors lui fournir l'item
frgInfos.setItem(item);
} else {
// lancer InfosActivity pour afficher l'item
Intent intent = new Intent(this, InfosActivity.class);
intent.putExtra("item", item);
startActivity(intent);
}
}

94
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

5.3.20. Relation entre deux classes mditer, partie 1


Une classe active capable davertir un couteur dun vnement. Elle dclare une interface que
doit implmenter lcouteur.

public class Classe1 {


public interface OnEvenementListener {
public void onEvenement(int param);
}
private OnEvenementListener ecouteur = null;
public void setOnEvenementListener(
OnEvenementListener objet) {
ecouteur = objet;
}
private void traitementInterne() {
...
if (ecouteur!=null) ecouteur.onEvenement(argument);
}
}

5.3.21. mditer, partie 2


Une 2e classe en tant qucouteur des vnements dun objet de Classe1, elle implmente linterface
et se dclare auprs de lobjet.

public class Classe2 implements Classe1.OnEvenementListener


{
private Classe1 objet1;

public Classe2() {
...
objet1.setOnEvenementListener(this);
}

public void onEvenement(int param) {


...
}
}

5.4. Prfrences dapplication


5.4.1. Illustration
Les prfrences mmorisent des choix de lutilisateur entre deux excutions de lapplication.

5.4.2. Prsentation
Il y a deux concepts mis en jeu :

95
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 38: Prfrences de lapplication

Une activit pour afficher et modifier les prfrences.


Une sorte de base de donnes qui stocke les prfrences,
boolens,
nombres : entiers, rels. . . ,
chanes et ensembles de chanes.
Chaque prfrence possde un identifiant. Cest une chane comme "prefs_nbmax". La base de
donnes stocke une liste de couples (identifiant, valeur).
Voir la documentation Android

5.4.3. Dfinition des prfrences


Dabord, construire le fichier res/xml/preferences.xml :

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


<PreferenceScreen xmlns:android="...">
<CheckBoxPreference android:key="prefs_online"
android:title="En ligne"
android:summary="Connexion permanente au serveur"
android:defaultValue="true" />
<EditTextPreference android:key="prefs_nbmax"
android:title="Nombre Max"
android:summary="Nombre maximal d'lments lists"
android:inputType="number"
android:numeric="integer"
android:defaultValue="100" />
...
</PreferenceScreen>

5.4.4. Explications
Ce fichier xml dfinit la fois :
Les prfrences :
lidentifiant : android:key
le titre rsum : android:title
le sous-titre dtaill : android:summary
la valeur initiale : android:defaultValue

96
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

La mise en page. Cest une sorte de layout contenant des cases cocher, des zones de saisie. . .
Il est possible de crer des pages de prfrences en cascade comme par exemple, les prfrences
systme.
Consulter la doc pour connatre tous les types de prfrences.
NB: le rsum naffiche malheureusement pas la valeur courante. Consulter stackoverflow pour une
proposition.

5.4.5. Accs aux prfrences


Les prfrences sont gres par une classe statique appele PreferenceManager. On doit lui demander
une instance de SharedPreferences qui reprsente la base et qui possde des getters pour chaque
type de donnes.

// rcuprer la base de donnes des prfrences


SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());

// rcuprer une prfrence boolenne


boolean online = prefs.getBoolean("prefs_online", true);

Les getters ont deux paramtres : lidentifiant de la prfrence et la valeur par dfaut.

5.4.6. Prfrences chanes et nombres


Pour les chanes, cest getString(identifiant, dfaut).

String hostname = prefs.getString("prefs_hostname","localhost");

Pour les entiers, il y a bug important (fvrier 2015). La mthode getInt plante. Voir stackoverflow
pour une solution. Sinon, il faut passer par une conversion de chane en entier :

int nbmax = prefs.getInt("prefs_nbmax", 99); // PLANTE


int nbmax =
Integer.parseInt(prefs.getString("prefs_nbmax", "99"));

5.4.7. Modification des prfrences par programme


Il est possible de modifier des prfrences par programme, dans la base SharedPreferences, laide
dun objet appel editor qui possde des setters. Les modifications font partie dune transaction
comme avec une base de donnes.
Voici un exemple :

// dbut d'une transaction


SharedPreferences.Editor editor = prefs.edit();
// modifications
editor.putBoolean("prefs_online", false);

97
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

editor.putInt("prefs_nbmax", 20);
// fin de la transaction
editor.commit();

5.4.8. Affichage des prfrences


Il faut crer une activit toute simple :
public class PrefsActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.prefs_activity);
}
}

Le layout prefs_activity.xml contient seulement un fragment :


<fragment xmlns:android="..."
android:id="@+id/frag_prefs"
android:name="LE.PACKAGE.COMPLET.PrefsFragment"
... />

Mettre le nom du package complet devant le nom du fragment.

5.4.9. Fragment pour les prfrences


Le fragment PrefsFragment hrite de PreferenceFragment :
public class PrefsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// charger les prfrences
addPreferencesFromResource(R.xml.preferences);
// mettre jour les valeurs par dfaut
PreferenceManager.setDefaultValues(
getActivity(), R.xml.preferences, false);
}
}

Cest tout. Le reste est gr automatiquement par Android.

5.5. Bibliothque support


5.5.1. Compatibilit des applications
Android est un systme destin de trs nombreux types de tablettes, tlphones, lunettes, montres
et autres. Dautre part, il volue pour offrir de nouvelles possibilits. Cela pose deux types de
problmes :

98
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Compatibilit des matriels,


Compatibilit des versions dAndroid.
Sur le premier aspect, chaque constructeur est cens faire en sorte que son appareil ragisse conform-
ment aux spcifications de Google. Ce nest pas toujours le cas quand les spcifications sont trop
vagues. Certains crent leur propre API, par exemple Samsung pour la camra.

5.5.2. Compatibilit des versions Android


Concernant lvolution dAndroid (deux versions du SDK par an, dont une majeure), un utilisateur
qui ne change pas de tlphone ce rythme est rapidement confront limpossibilit dutiliser des
applications rcentes.
Normalement, les tlphones devraient tre mis jour rgulirement, mais ce nest quasiment jamais
le cas.
Dans une application, le manifeste dclare la version ncessaire :

<uses-sdk android:minSdkVersion="17"
android:targetSdkVersion="25" />

Avec ce manifeste, si la tablette nest pas au moins en API niveau 17, lapplication ne sera pas installe.
Lapplication est garantie pour bien fonctionner jusqu lAPI 25 incluse.

5.5.3. Bibliothque support


Pour crer des applications fonctionnant sur de vieux tlphones et tablettes, Google propose une
solution depuis 2011 : une API alternative, Android Support Library . Ce sont des classes similaires
celles de lAPI normale, mais qui sont programmes pour fonctionner partout, quel que soit la
version du systme install.
Cest une approche intressante qui compense labsence de mise jour des tablettes : au lieu de
mettre jour les appareils, Google met jour la bibliothque pour que les dispositifs les plus rcents
dAndroid (ex: ActionBar, Fragments, etc.) fonctionnent sur les plus anciens appareils.

5.5.4. Versions de lAndroid Support Library


Il en existe plusieurs variantes, selon lanciennet quon vise. Le principe est celui de lattribut
minSdkVersion, la version de la bibliothque : v4, v7 ou v11 dsigne le niveau minimal exig pour le
matriel quon vise.
v4 : cest la plus grosse API, elle permet de faire tourner une application sur tous les appareils
depuis Android 1.6. Par exemple, elle dfinit la classe Fragment utilisable sur ces tlphones.
Elle contient mme des classes qui ne sont pas dans lAPI normale, telles que ViewPager.
v7-appcompat : pour les tablettes depuis Android 2.1. Par exemple, elle dfinit lActionBar.
Elle sappuie sur la v4.
Il y en a dautres, plus spcifiques, v8, v13, v17.

99
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

5.5.5. Mode demploi


La premire chose faire est de dfinir le niveau de SDK minimal ncessaire dans le manifeste.
Actuellement, dbut 2017, cest 9 :

<uses-sdk android:minSdkVersion="9" .../>

Ensuite, il faut modifier le script build.gradle :

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-compat:25.1.1'
compile 'com.android.support:support-core-utils:+'
}

On rajoute les lments ncessaires. Cest assez compliqu. Il y a la fois le nom : support-compat,
support-core-ui, support-core-utils, support-fragment, appcompat-v7. . . et un numro de
version complet, ou seulement + pour la plus rcente.

5.5.6. Programmation
Enfin, il suffit de faire appel ces classes pour travailler. Elles sont par exemple dans le package
android.support.v4.

import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity


...

Il y a de trs nombreuses classes et paquetages, cest difficile comprendre quand on dbute.


Le problme, cest quelles ont parfois le mme nom que les classes normales dAndroid, ex: Fragment,
FragmentActivity et parfois pas du tout, ex: AppCompatActivity. Il y a aussi des conflits inextri-
cables entre ces classes, ex: LoaderManager (voir la semaine prochaine).

5.5.7. Il est temps de faire une pause


Cest fini pour cette semaine, rendez-vous la semaine prochaine pour un cours sur les adaptateurs de
bases de donnes et les WebServices.

100
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Semaine 6

Bases de donnes SQLite3 <>

Aprs avoir reprsent une liste ditems sous forme dun tableau en semaine 4, nous allons la stocker
dans un SGBD SQL.

Figure 39: Logo de SQLite3

SQLite3
Requtes et curseurs
WebServices

6.1. SQLite3
6.1.1. Stockage dinformations
Il nest pas pertinent denregistrer des informations dans un tableau stock en mmoire vive, cest
dire sur un support volatile. Android contient un SGBD SQL appel SQLite3, parfait pour stocker
des informations durables.
Exemple en ligne de commande :
bash$ sqlite3
sqlite> CREATE TABLE Planetes (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
nom TEXT NOT NULL,
distance REAL);
sqlite> INSERT INTO Planetes VALUES (1, "Sedna", 12925.26);
sqlite> SELECT * FROM Planetes;
1|Sedna|12925.26
sqlite>

6.1.2. SQLite3
SQLite3 est un vrai SGBD relationnel SQL, mais simplifi pour tenir sur une tablette.
Ce qui lui manque :

101
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Aucune gestion des utilisateurs (autorisations), pas de scurit.


Pas de rglages pour amliorer les performances car
Peu de types de donnes, ex: date = entier ou chane, un seul type dentiers. . .
SQLite3 fonctionne sans serveur. Il stocke ses donnes dans un seul fichier. Ce fichier est portable,
cest dire copiable sur nimporte quelle autre machine.

6.1.3. Exemples SQL


Toutes les requtes SQL que vous connaissez fonctionnent, p. ex. :

SELECT COUNT(*) FROM Planetes WHERE nom LIKE 'Ter%';


SELECT * FROM Planete WHERE distance>200.0 ORDER BY distance;
SELECT AVG(distance) AS moyenne FROM Planetes;
DELETE FROM Planetes WHERE distance IS NULL;
ALTER TABLE Planetes ADD COLUMN date INTEGER;
UPDATE Planetes SET distance=12775.66 WHERE _id=1;
DROP TABLE Planetes;

Jointures, groupements, requtes imbriques, transactions, index, triggers. . . tout cela est possible.
Consulter la documentation.

6.1.4. Autres usages de SQLite3


Ce SGBD est utilis dans de nombreuses applications ailleurs que dans Android, p. ex. dans Firefox
pour stocker les marque-pages, lhistorique de navigation, etc.
SQLite3 fournit aussi une API pour diffrents langages de programmation : C, Python, PHP, Java. . .
On peut excuter des requtes SQL en appelant des fonctions.
Android propose cette API aux programmeurs pour stocker des informations structures, plutt que
bricoler avec des fichiers. Cest assez facile utiliser une fois le cadre mis en place.

6.1.5. Lancement de sqlite3 en shell


En ligne de commande, sqlite3 ouvre une session SQL. Il ny a pas de connexion un serveur, donc
pas de mot de passe.
On peut fournir un paramtre, cest le nom dun fichier qui contient la base. Si on ne fournit pas ce
nom, alors la base nest quen mmoire, perdue quand on quitte.

bash$ sqlite3 planetes.db


sqlite>

Cette commande est dans le dossier du SDK, sous-dossier platform-tools (Linux et Windows). Elle
nest pas forcment incluse dans le systme Linux de la tablette.

102
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.1.6. Commandes internes


Le shell de SQLite3 possde des commandes internes, p. ex. :
.help affiche la liste des commandes internes
.tables affiche la liste des tables
.indices table affiche la liste des index de la table si elle est fournie, toutes sinon
.schema table affiche la structure de la table (toutes si pas de nom fourni)
.dump table affiche le contenu de la table ou de toute la base si la table est omise
.headers mettre on ou off pour crire les noms des colonnes en tte de tous les select
.exit sort du shell sqlite3, CTRL-D le fait aussi.

6.2. SQLite dans une application Android


6.2.1. Bases de donnes Android
Chaque application peut crer une base de donnes. Cest un fichier *.db plac dans le dossier
/data/data/PAQUETAGE/databases/NOM_BDD
Remarque : le chemin exact peut varier selon les tablettes et AVD.

Vous pourrez changer ce fichier avec le PC (adb push ou pull). Consulter cette page pour des
dtails sur la marche suivre.
Dans une application Android, ces fichiers sont manipuls laide de classes de lAPI.
NB: ce cours commence par une grande simplification (louverture dune BDD). Lisez la totalit pour
savoir comment on procde en ralit.

6.2.2. Classes pour travailler avec SQLite


Il faut connatre au moins deux classes :
SQLiteDatabase : elle reprsente une BDD. Ses mthodes permettent dexcuter une requte,
par exemple :
void execSQL(String sql) pour CREATE, ALTER, DROP. . . qui ne retournent pas de
donnes.
Cursor rawQuery(String sql, ...) pour des SELECT qui retournent des n-uplets.
Dautres mthodes pour des requtes spcialises.
Cursor : reprsente un n-uplet. Il y a des mthodes pour rcuprer les colonnes.
Voyons les dtails.

6.2.3. tapes du travail avec une BDD


Voici les tapes du travail avec une BDD en Java :
1. Ouverture de la base, cration du fichier si besoin :
SQLiteDatabase bdd;
bdd = SQLiteDatabase.openOrCreateDatabase(...);
2. Excution de requtes :
1. Obtention dun curseur sur le rsultat des select
Cursor cursor = bdd.rawQuery(requete, ...);

103
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

2. Parcours des n-uplets du curseur laide dune boucle for


3. Fermeture du curseur (indispensable, prvoir les exceptions, voir plus loin)
cursor.close()
3. Fermeture de la base (indispensable, prvoir les exceptions) :
bdd.close()

6.2.4. Base ouverte dans une activit


Il est prfrable douvrir la base pour toute la vie de lactivit dans onCreate, et la fermer dans la
mthode onDestroy :

class MonActivite extends Activity


{
private SQLiteDatabase bdd;

void onCreate(...) {
...
bdd = SQLiteDatabase.openOrCreateDatabase(...);
}

void onDestroy() {
...
bdd.close();
}
}

6.2.5. Patron de conception pour les requtes


Il est trs conseill de dfinir une classe associe chaque table (et mme chaque jointure). a
permet de faire voluer le logiciel assez facilement. Cette classe regroupe toutes les requtes SQL la
concernant : cration, suppression, mise jour, parcours, insertions. . . sous forme de mthodes de
classe. La base de donnes est passe en premier paramtre de toutes les mthodes.
Cette dmarche sinspire du patron de conception Active Record qui reprsente une table par une
classe. Ses instances sont les n-uplets de la table. Les attributs de la table sont grs par des accesseurs
et mutateurs. Des mthodes comme find permettent de rcuprer des n-uplets et dautres mthodes
permettent la mise jour de la base : new, save et delete.
Voir le projet ActiveAndroid pour une implantation Android.

6.2.6. Noms des colonnes


Dans ce cours, on va mettre en uvre une simplification de ce patron de conception.
On dfinit une classe ne contenant que des mthodes statiques.

public class TablePlanetes


{
// mthodes statiques pour grer les donnes

104
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

public static create(...) ...

public static drop(...) ...

public static insert(...) ...

...
}

6.2.7. Classe pour une table


Par exemple, pour crer et supprimer la table :

public static void create(SQLiteDatabase bdd)


{
bdd.execSQL( "CREATE TABLE Planetes (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"nom TEXT NOT NULL," +
"distance REAL)");
}

public static void drop(SQLiteDatabase bdd)


{
bdd.execSQL("DROP TABLE IF EXISTS Planetes");
}

Gare la syntaxe, a doit crer du SQL correct !

6.2.8. Exemples de mthodes


Voici des mthodes pour crer ou supprimer des n-uplets :

public static void insert(SQLiteDatabase bdd, Planete pl)


{
bdd.execSQL(
"INSERT INTO Planetes VALUES (null, ?, ?)",
new Object[] { pl.getNom(), pl.getDistance() });
}
public static void delete(SQLiteDatabase bdd, long id)
{
bdd.execSQL(
"DELETE FROM Planetes WHERE _id=?",
new Object[] {id});
}

On va aussi rajouter des mthodes de consultation des donnes mais avant, voyons la mthode
execSQL.

105
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.2.9. Mthodes SQLiteDatabase.execSQL


Cette mthode excute une requte SQL qui ne retourne pas dinformations : CREATE, INSERT. . . Elle
a deux variantes :
void execSQL (String sql) : on doit juste fournir la requte sous forme dune chane. Cest
une requte constante. Ne pas mettre de ; la fin. Par exemple :

bdd.execSQL("DROP TABLE Planetes");

void execSQL (String sql, Object[] bindArgs) : cest pour le mme type de requte mais
contenant des jokers ? affecter avec les objets fournis en paramtre.

bdd.execSQL("DELETE FROM Planetes WHERE _id BETWEEN ? AND ?",


new Object[] { 3, 8 });

6.2.10. Mthodes spcialises


Android propose des mthodes spcifiques pour insrer, modifier, supprimer des n-uplets :
int insert(String table, null, ContentValues valeurs)
int update(String table, ContentValues valeurs, String whereClause, String[]
whereArgs)
int delete(String table, String whereClause, String[] whereArgs)
La diffrence avec execSQL, cest quelles demandent un tableau de String. Il faut donc convertir
toutes les donnes en chanes.

6.2.11. Mthode insert


insert(table, null, valeurs) effectue une requte du type :

INSERT INTO table (col1, col2...) VALUES (val1, val2...);

Elle retourne lidentifiant du nouveau n-uplet. Ses paramtres sont :


table : fournir le nom de la table
null sauf si vous voulez faire un INSERT INTO table; sans fournir aucune valeur (valeurs
toutes par dfaut)
valeurs : cest une structure du type ContentValues qui associe des noms et des valeurs
quelconques :

ContentValues valeurs = new ContentValues();


valeurs.putNull("_id");
valeurs.put("nom", "Sedna");
int id = bdd.insert("Planetes", null, valeurs);

106
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.2.12. Mthodes update et delete


update(table, valeurs, whereClause, whereArgs) fait UPDATE table SET col1=val1,
col2=val2 WHERE ...; et delete(table, whereClause, whereArgs) effectue DELETE FROM
table WHERE ...; Elles retournent le nombre de n-uplets altrs. Les paramtres sont :
table : fournir le nom de la table
valeurs : ce sont les couples (colonne, valeur mettre)
whereClause : une condition contenant des jokers ?
whereArgs : chanes mettre la place des ?
ContentValues valeurs = new ContentValues();
valeurs.put("nom", "Sedna");
bdd.update("Planetes", valeurs, "_id=?", new String[] { "4" });
bdd.delete("Planetes","_id BETWEEN ? AND ?",new String[]{"5","8"});

6.2.13. Mthode rawQuery


Cette mthode, rawQuery permet dexcuter des requtes de type SELECT. Elle retourne un objet
Java de type Cursor qui permet de parcourir les n-uplets un un :
Cursor cursor = bdd.rawQuery("SELECT * FROM table WHERE...");
if (cursor != null) {
try {
if (cursor.moveToFirst()) { // obligatoire
while (!cursor.isAfterLast()) { // test de fin
...utiliser le curseur...
cursor.moveToNext(); // n-uplet suivant
}
}
} finally {
cursor.close();
}

6.2.14. rawQuery pour un seul n-uplet


Sil ny a quun seul n-uplet dans la rponse, il nest pas ncessaire de faire une boucle, mais il faut
quand mme initialiser le curseur par moveToFirst et le fermer la fin :
Cursor cursor = bdd.rawQuery("SELECT MAX(distance) FROM Planetes");
if (cursor != null) {
try {
if (cursor.moveToFirst()) { // obligatoire
float distmax = cursor.getFloat(0);
}
} finally {
cursor.close(); // obligatoire
}
}

107
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Le finally garantit la fermeture du curseur, mme en cas dexception et de return dans le try.

6.2.15. Classe Cursor


La classe Cursor propose deux types de mthodes :
celles qui permettent de parcourir les n-uplets :
getCount() : retourne le nombre de n-uplets,
getColumnCount() : retourne le nombre de colonnes,
moveToFirst() : place le curseur sur le premier n-uplet,
isAfterLast() : retourne vrai si le parcours est fini,
moveToNext() : passe au n-uplet suivant.
celles qui permettent dobtenir la valeur de la colonne nnc allant de 0 getColumnCount()-1
du n-uplet courant :
getColumnName(nc) : retourne le nom de la colonne nc,
isNull(nc) : vrai si la colonne nc est nulle,
getInt(nc), getLong(nc), getFloat(nc), getString(nc), etc. : valeur de la colonne nc.

6.2.16. Exemple de requte, classe TablePlanetes

public static String getNom(SQLiteDatabase bdd, long id)


{
Cursor cursor = bdd.rawQuery(
"SELECT nom FROM Planetes WHERE _id=?",
new String[] {Long.toString(id)});
if (cursor == null) return null;
try {
if (cursor.moveToFirst() && !cursor.isNull(0)) {
return cursor.getString(0);
} else
return null;
} finally {
cursor.close();
}
}

6.2.17. Autre type de requte


Cette autre mthode retourne non pas une valeur, mais directement un curseur. Elle est utilise pour
afficher tous les lments de la table dans une liste, voir page 113.
public static Cursor getAll(SQLiteDatabase bdd)
{
return bdd.rawQuery("SELECT * FROM Planetes", null);
}

Attention, votre application doit prendre soin de fermer ce curseur ds quil ne sert plus, ou alors de
le fournir un objet (ex: un adaptateur) qui sait le fermer automatiquement.

108
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.2.18. Mthodes query : sans aucun intrt


Android propose galement des mthodes pratiques pour effectuer des requtes, telles que :

query(String table, String[] columns, String selection,


String[] selectionArgs, String groupBy, String having,
String orderBy, String limit)

mais je ne vois pas lintrt de recoder en Java ce qui se fait parfaitement en SQL, sans compter les
risques derreur si on permute involontairement les paramtres de ces mthodes.

6.2.19. Ouverture dune base


Revenons vers les aspects gestion interne de la base de donnes. Louverture dune base se fait ainsi :

String path = this.getFilesDir().getPath().concat("/test.db");


SQLiteDatabase bdd =
SQLiteDatabase.openOrCreateDatabase(path, null);

NB: cela ne cre pas les tables, seulement le fichier qui contient la base.
Il faut fournir le chemin daccs la base. Mais en faisant ainsi, la base est cre dans
/data/data/*package*/files et non pas .../databases. Voir page 108 pour la vritable faon de
faire.

6.2.20. Premire ouverture et ouvertures suivantes


Ensuite, aprs avoir ouvert la base, si cest la premire fois, il faut crer les tables. Cependant, a
cause une erreur de crer une table qui existe dj et il serait coteux de tester lexistence des tables.
Une possibilit consiste rajouter IF NOT EXISTS la requte de cration. Par exemple :

bdd.execSQL(
"CREATE TABLE IF NOT EXISTS Planetes (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"nom TEXT NOT NULL)");

Un autre problme, cest la mise jour de lapplication. Quallez-vous proposer vos clients si vous
changez le schma de la base entre la V1 et la V2, la V2 et la V3. . . ?

6.2.21. Un helper pour grer louverture/cration/mj


Android propose la classe supplmentaire SQLiteOpenHelper qui facilite la gestion des bases de
donnes. Il faut programmer une drivation de cette classe en surchargeant deux mthodes :
onCreate(bdd) : cette mthode est appele quand la base de donnes nexiste pas encore. Son
rle est de crer les tables. Cest l que vous mettez les CREATE TABLE...

109
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

onUpgrade(bdd, int oldV, int newV) : cette mthode est appele quand la version de
lapplication est suprieure celle de la base. Son rle peut tre de faire des ALTER TABLE...,
UPDATE....
Les mthodes getReadableDatabase et getWritableDatabase de SQLiteOpenHelper ouvrent la
base et appellent automatiquement onCreate et onUpgrade si ncessaire.

6.2.22. Exemple de helper

public class MySQLiteHelper extends SQLiteOpenHelper


{
// nom du fichier contenant la base de donnes
private static final String DB_NAME = "test.db";

// version du schma de la base de donnes


private static final int DB_VERSION = 1;

// constructeur du helper = ouvre et cre/mj la base


public MySQLiteHelper(Context context)
{
super(context, DB_NAME, null, DB_VERSION);
}

...

6.2.23. Exemple de helper, suite

@Override
public void onCreate(SQLiteDatabase bdd)
{
// cration avec la mthode de la classe TablePlanetes
TablePlanetes.create(bdd);
}
@Override
public void onUpgrade(SQLiteDatabase bdd,
int oldVersion, int newVersion)
{
// suppression de toutes les donnes !
TablePlanetes.drop(bdd);
// re-cration de la base
onCreate(bdd);
}
}

110
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.2.24. mthode onUpgrade

public void onUpgrade(SQLiteDatabase bdd,


int oldVersion, int newVersion)

Dans le cas dune application srieuse, on ne dtruit pas toutes les donnes utilisateur quand on change
le schma. Cest vous de dterminer les modifications minimales qui permettent de transformer les
donnes prsentes, de leur version actuelle oldVersion la version newVersion.
Il est indiqu de procder par tapes :
passer de la version oldVersion la oldVersion+1
passer de la version oldVersion+1 la oldVersion+2
ainsi de suite, jusqu arriver la newVersion.

6.2.25. mthode onUpgrade, suite


Cela donne quelque chose comme a :

@Override
public void onUpgrade(..., int oldVersion, int newVersion){
while (oldVersion < newVersion) {
switch (oldVersion) {
case 1: // amener la base de la V1 la V2
bdd.execSQL("ALTER TABLE Planetes ADD COLUMN taille REAL");
break;
case 2: // amener la base de la V2 la V3
...
break;
}
oldVersion++;
}
}

6.2.26. Retour lapplication


Avec un helper, cela devient trs simple douvrir une base, en consultation seule ou en modification :

MySQLiteHelper helper = new MySQLiteHelper(this);


SQLiteDatabase bdd = helper.getReadableDatabase();
/* ou bien */
SQLiteDatabase bdd = helper.getWritableDatabase();

// requtes SQL sur l'objet bdd


...

A la terminaison de lapplication, cest le helper quil faut fermer, et cest lui qui ferme la base :

111
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

helper.close();

6.3. CursorAdapter et Loaders


6.3.1. Lien entre une BDD et un ListView
On revient vers lapplication qui affiche une liste. Cette fois, la liste doit tre le rsultat dune requte
SELECT. Comment faire ?
Les choses sont devenues relativement complexes depuis Android 3. Afin dviter que lapplication se
bloque lors du calcul de la requte et voir le message lapplication ne rpond pas , Android emploie
un mcanisme appel chargeur, loader en anglais.
Le principe est de rendre le calcul de la requte SQL asynchrone, dsynchronis de linterface. On
lance la requte SELECT et en mme temps, on affiche une liste vide. Lorsque la requte sera finie, la
liste sera mise jour, mais en attendant, linterface ne reste pas bloque.

6.3.2. tapes suivre


Mthode onCreate de lactivit qui affiche la liste :
1. Dfinir un adaptateur de curseur pour la liste
2. Ouvrir la base de donnes
3. Crer un chargeur de curseur et lassocier this
4. Dmarrer le chargeur
Dfinir la classe MonCursorLoader, sous-classe de CursorLoader qui effectue la requte SQL
Dfinir trois callbacks :
onCreateLoader : retourne un MonCursorLoader
onLoadFinished et onLoaderReset : reoivent un curseur jour et mettent jour
ladaptateur
Voici le dtail.

6.3.3. Activit ou fragment daffichage dune liste


Cette activit hrite de ListActivity (ou ListFragment) et elle implmente les mthodes dun
chargeur de curseur :

public class MainActivity extends ListActivity


implements LoaderManager.LoaderCallbacks<Cursor>
{
private MySQLiteHelper helper;
private SQLiteDatabase bdd;
private SimpleCursorAdapter adapter;

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

112
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

setContentView(R.layout.main);
...

6.3.4. Cration dun adaptateur de curseur


a ressemble ladaptateur dun tableau, mais on fournit deux listes : les noms des colonnes et les
identifiants des vues dans lesquelles il faut mettre les valeurs.

// crer un adaptateur curseur-liste


adapter = new SimpleCursorAdapter(this,
// layout des lments de la liste
android.R.layout.simple_list_item_2,
// le curseur sera charg par le loader
null,
// noms des colonnes afficher
new String[]{"nom", "distance"},
// identifiants des TextView qui affichent les colonnes
new int[]{android.R.id.text1, android.R.id.text2},
0); // options, toujours mettre 0
setListAdapter(adapter);

6.3.5. Ouverture de la base et cration dun chargeur


Ensuite, toujours dans la mthode onCreate de lactivit, on ouvre la base, ici en consultation car
cette activit ne modifie pas les donnes, puis on cre un chargeur associ this.

// identifiant du chargeur (utile s'il y en a plusieurs)


private static final int LOADER_LISTE_PLANETES = 1;
// ouvrir la base de donnes SQLite
helper = new MySQLiteHelper(this);
bdd = helper.getReadableDatabase();
// cre et dmarre un chargeur pour cette liste
getLoaderManager().initLoader(LOADER_LISTE_PLANETES,null,this);

Cette dernire instruction exige de dfinir trois callbacks dans lactivit : onCreateLoader,
onLoadFinished et onLoaderReset. Voyons dabord la premire.

6.3.6. Callback onCreateLoader de lactivit


Toujours dans la classe dactivit qui affiche la liste :

@Override
public Loader<Cursor> onCreateLoader(int loaderID,
Bundle bundle)
{
return new MonCursorLoader(getApplicationContext(), bdd);
}

113
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Cette callback fait instancier un MonCursorLoader qui est une sous-classe de CursorLoader, dfinie
dans notre application, voir le transparent suivant. Son rle est de lancer la requte qui retourne le
curseur contenant les donnes afficher.

6.3.7. classe MonCursorLoader

static private class MonCursorLoader extends CursorLoader


{
private SQLiteDatabase bdd;

public MonCursorLoader(Context context, SQLiteDatabase bdd) {


super(context);
this.bdd = bdd;
}
@Override
protected Cursor onLoadInBackground() {
return TablePlanetes.getAll(bdd);
}

Voir page 107 pour la mthode getAll, elle fait seulement return bdd.rawQuery("SELECT * FROM
Planetes", null);

6.3.8. Callback onLoadFinished de lactivit


Pour finir, la callback qui est appele lorsque les donnes sont devenues disponibles ; elle met jour
ladaptateur, ce qui affiche les n-uplets dans la liste. Lautre callback est appele si le chargeur doit
tre supprim. On met donc toujours ceci :

@Override
public void onLoadFinished(Loader<Cursor> loader,
Cursor cursor) {
adapter.changeCursor(cursor);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.changeCursor(null);
}

6.3.9. Mise jour de la liste


Quand il faut mettre jour la liste, si les donnes ont chang, il faut relancer le chargeur de curseur
et non pas ladaptateur. Cela se fait de la manire suivante :

114
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

// le chargeur doit recommencer son travail


getLoaderManager().restartLoader(LOADER_LISTE_PLANETES,null,this);

6.3.10. En mode compatibilit


Si vous utilisez la bibliothque support appcompat-v7, le type du LoaderManager est spcifique.
Il faut que votre activit hrite de AppCompatActivity, et le LoaderManager sobtient par
getSupportLoaderManager().

6.4. ContentProviders
6.4.1. Prsentation rapide
Les Fournisseurs de contenu sont des sortes de tables de donnes disponibles dune application
lautre et accessibles laide dun URI (gnralisation dun URL). Un exemple est le carnet dadresse
de votre tlphone. Dautres applications que la tlphonie peuvent y avoir accs.
Un ContentProvider possde diffrentes mthodes ressemblant celles des bases de donnes :
query : retourne un Cursor comme le fait un SELECT,
insert, update, delete : modifient les donnes,
Dautres mthodes permettent de consulter le type MIME des donnes.
Comme cest trs compliqu mettre en uvre et que a ressemble une simple table SQL sans
jointure, on nen parlera pas plus ici.

6.5. WebServices
6.5.1. Base de donne distante
Remarque : cette partie de cours concerne les bases de donnes mais sera prsente en semaine 7,
avec les AsyncTask et requtes HTTP.
On arrive au plus intressant, faire en sorte quune application Android stocke ses donnes sur un
serveur distant. Pour commencer, rvisez vos cours de Web Design, PHP, PDO. . .

6.5.2. change entre un serveur SQL et une application Android


Soit un serveur HTTP connect une base de donnes (PostgreSQL en TP). Ce serveur possde des
scripts PHP qui vont rpondre aux demandes de lapplication Android laide dau moins deux types
dchanges HTTP4 :
Les SELECT vont tre traites par des GET,
Les INSERT, UPDATE, DELETE. . . vont tre envoys par des POST.
Chaque requte sera associe un script spcifique.
4
En fait, un vrai WebService Restful est plus complexe, voir wikipedia

115
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.5.3. Principe gnral


Soit la requte SELECT * FROM Planetes WHERE _id=3. On va envoyer lidentifiant 3 sur le rseau
et cest un script PHP qui va effectuer la requte. Il y a un script par sorte de requte, donc chacun
sait exactement quels paramtres il va recevoir.
1. Lapplication construit une requte HTTP, p. ex. de type GET
URL = http://serveur/script?paramtres
paramtres = conditions du select, p. ex. identifiant=3.
2. Lapplication (cliente) envoie cette requte au serveur puis attend la rponse,
3. Le script PHP excute la requte puis retourne le rsultat encod en JSON lapplication,
4. Lapplication dcode le rsultat et laffiche.
Les autres requtes suivent le mme principe client-serveur.

6.5.4. Exemple de script PHP Post


Voici un script qui modifie un n-uplet. Il est lanc par un POST.

// connexion au serveur SQL par PDO


$db = new PDO("pgsql:host=$hostname;dbname=$dbname",
$login, $passwd);

// paramtres de la requte (TODO: tester la prsence)


$id = $_POST['_id'];
$nom = $_POST['nom'];

// prparation et excution
$query = $db->prepare(
"UPDATE Planetes SET nom=? WHERE _id=?");
$query->execute(array($nom, $id));

NB: ici, on se ne proccupe pas de scurit.

6.5.5. Exemple de script PHP Get


Voici get_all_planetes.php qui retourne tous les n-uplets :

// connexion au serveur SQL par PDO


$db = new PDO("pgsql:host=$hostname;dbname=$dbname",
$login, $passwd);

// liste de tous les types


$query = $db->prepare("SELECT * FROM Planetes ORDER BY _id;");
$query->execute();

// encodage JSON de toutes les rponses


echo json_encode($query->fetchAll(PDO::FETCH_NUM));

116
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.5.6. Format JSON JavaScript Object Notation


Cest un format concurrent de XML pour transporter des tableaux et des objets travers le rseau.
Ils sont crits sous forme dun texte.
Par exemple la liste des n-uplets prsents dans la table Planetes :
[[1,"Mercure",58],[2,"Venus",108],[3,"Terre",150],...

En PHP, cest trs simple :


// encodage : tableau -> jsondata
$jsondata = json_encode($tableau);
// dcodage : jsondata -> tableau
$tableau = json_decode($jsondata);

Le tableau peut venir dun fetchAll(PDO::FETCH_NUM).

6.5.7. JSON en Java


Dcoder le JSON en Java est plus compliqu. Il faut employer une instance de JSONArray. Elle
possde des setters et des getters pour chaque type de donnes.
// encodage : tableau -> jsondata
int[] tableau = new int[] { 2, -7, 5 };
JSONArray ja = new JSONArray();
for (int v: tableau) ja.put(v);
String jsondata = ja.toString();
// dcodage : jsondata -> tableau
JSONArray ja = new JSONArray(jsondata);
final int nb = ja.length();
int[] tableau = new int[nb];
for (int i=0; i<nb; i++) tableau[i] = ja.getInt(i);

Cest adapter aux donnes changer : entiers, chanes. . .

6.5.8. Dans lapplication Android


Tout le problme est de construire une requte HTTP, dattendre la rponse, de la dcoder et de
lafficher.
Pour commencer, il faut que lapplication soit autorise accder internet. Rajouter cette ligne
dans le manifeste :
<uses-permission android:name="android.permission.INTERNET"/>

Ensuite, il faut transformer tout ce qui est requte SQL :


Affichage des donnes : changer le chargeur de curseur,
Modifications des donnes.
Voyons cela dans lordre.

117
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

6.5.9. Affichage dune liste


Il suffit de reprogrammer la mthode getAll de la classe TablePlanetes, voir page 107 et 115 :

public static Cursor getAll(RemoteDatabase bdd)


{
// requte Get l'aide de la classe RemoteDatabase
String jsondata = bdd.get("get_all_planetes.php", null);
// dcoder les n-uplets et en faire un curseur
return bdd.cursorFromJSON(jsondata,
new String[] { "_id", "nom", "distance" });
}

Jai retir les tests derreur et traitements dexceptions.

6.5.10. La classe RemoteDatabase


Cest une classe que je vous propose. Elle fait un peu tout : le caf, les croissants. . . Cest elle qui
organise la communication avec le serveur, dont ces mthodes :
get("script.php", params) appelle le script PHP par un GET en lui passant les paramtres
indiqus et retourne un String contenant la rponse du serveur sous forme de donnes JSON.
cursorFromJSON(jsondata, noms_des_colonnes) construit un curseur avec la rponse JSON
du serveur. On est oblig de fournir les noms des colonnes car ils ne sont pas prsents dans les
donnes JSON.
Cette classe est assez complexe. Une partie des explications viendra la semaine prochaine.

6.5.11. Modification dun n-uplet


Voici maintenant une requte POST pour modifier un n-uplet :

public static void update(RemoteDatabase bdd, Planete pl,


RemoteDatabaseListener listener)
{
// paramtres de la requte
ContentValues params = new ContentValues();
params.put("_id", pl.getId());
params.put("nom", pl.getNom());

// requte Post asynchrone


bdd.post(listener, "update_planete.php", params);
}

Elle appelle le script update_planete.php suivant.

6.5.12. Script update_planete.php


Avant dexpliquer la mthode post de la classe RemoteDatabase, voici le script update_planete.php
qui est dclench par la requte du transparent prcdent :

118
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

// connexion la base de donnes


$db = new PDO("pgsql:host=".$hostname.";dbname=".$dbname,
$login, $passwd);
// paramtres de la requte
$id = $_POST['_id'];
$nom = $_POST['libelle'];
// prparation et excution
$query = $db->prepare("UPDATE Planetes SET nom=? WHERE _id=?");
$query->execute(array($nom, $id));

6.5.13. Mthode post(couteur, script, params)


La mthode post(couteur, script, params) appelle un script PHP en lui fournissant des
paramtres. Par exemple, cest le script update_type.php avec les paramtres _id et libelle.
Elle a une particularit : cette mthode est asynchrone. Cest dire quelle lance un change rseau
en arrire-plan, et nattend pas quil se termine. Cest obligatoire, sinon Android affiche une erreur :
lapplication ne rpond pas, dialogue ANR .

Figure 40: Dialogue ANR

6.5.14. Principe de la mthode post


Le script PHP appel peut durer un certain temps : connexion rseau et travail du serveur. Pour ne
pas bloquer lapplication, la mthode post doit travailler en arrire-plan, comme avec le shell dUnix,
mais pouvoir prvenir lapplication quand elle a fini.
Le principe pour cela est de crer une AsyncTask. Elle gre une action qui est excute dans un autre
thread que celui de linterface. On verra cela la semaine prochaine.
Du coup, il faut un couteur prvenir quand laction est termine. Cest le premier paramtre pass
la mthode post. Par exemple, cest lactivit daffichage de liste qui peut alors mettre jour la
liste affiche.

6.5.15. Cest tout pour aujourdhui


Cest fini pour cette semaine, rendez-vous la semaine prochaine pour un cours sur les accs rseau
asynchrones ainsi que la cartographie OpenStreetView.

119
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Semaine 7

Affichage de donnes golocalises

Cette semaine est consacre lAPI de cartographie OpenStreetMap mais auparavant quelques
concepts importants connatre : les tches asynchrones et les requtes rseau.

7.1. AsyncTasks
7.1.1. Prsentation
Une activit Android repose sur une classe, ex MainActivity qui possde diffrentes mthodes comme
onCreate, les couteurs des vues, des menus et des chargeurs.
Ces fonctions sont excutes par un seul processus lger, un thread appel Main thread . Il dort la
plupart du temps, et ce sont les vnements qui le rveillent.
Ce thread ne doit jamais travailler plus de quelques fractions de secondes sinon linterface parat
bloque et Android peut mme dcider que lapplication est morte (App Not Responding).

Figure 41: Application bloque

7.1.2. Tches asynchrones


Pourtant dans certains cas, une callback peut durer longtemps :
gros calcul
requte SQL un peu complexe
requte rseau
La solution passe par une sparation des threads, par exemple laide dune tche asynchrone
AsyncTask. Cest un autre thread, indpendant de linterface utilisateur, comme un job Unix.
Lancer un AsyncTask ressemble faire commande & en shell.
Linterface utilisateur peut tre mise jour de temps en temps par la AsyncTask. Il est galement
possible de rcuprer des rsultats la fin de lAsyncTask.

120
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

7.1.3. Principe dutilisation dune AsyncTask


Ce qui est mauvais :
1. Android appelle la callback de lactivit, ex: onClick,
2. La callback a besoin de 20 secondes pour faire son travail,
3. Mais au bout de 5 secondes, Android propose de tuer lapplication.
Ce qui est correct :
1. Android appelle la callback de lactivit,
2. La callback cre une AsyncTask puis sort immdiatement,
3. Le thread de lAsyncTask travaille pendant 20 secondes,
4. Pendant ce temps, linterface est vide, mais reste ractive,
5. LAsyncTask affiche les rsultats sur linterface ou appelle un couteur.

7.1.4. Structure dune AsyncTask


Une tche asynchrone est dfinie par plusieurs mthodes :
Constructeur permet de passer des paramtres la tche.
onPreExecute Initialisation effectue par le thread principal, p. ex. elle initialise une barre
davancement (ProgressBar).
doInBackground Cest le corps du traitement. Cette mthode est lance dans son propre thread.
Elle peut durer autant quon veut.
onProgressUpdate Cette mthode permet de mettre jour linterface, p. ex. la barre davancement.
Pour a, doInBackground doit appeler publishProgress.
onPostExecute Elle est appele quand lAsyncTask a fini, par exemple pour masquer la barre
davancement et mettre jour les donnes sur linterface.

7.1.5. Paramtres dune AsyncTask


Ce qui est difficile comprendre, cest que AsyncTask est une classe gnrique (comme ArrayList).
Elle est paramtre par trois types de donnes :

AsyncTask<Params, Progress, Result>

Params est le type des paramtres de doInBackground,


Progress est le type des paramtres de onProgressUpdate,
Result est le type du paramtre de onPostExecute qui est aussi le type du rsultat de
doInBackground.
NB: a ne peut tre que des classes, donc Integer et non pas int, et Void au lieu de void (dans ce
dernier cas, faire return null;).

7.1.6. Exemple de paramtrage


Soit une AsyncTask qui doit interroger un serveur mto pour savoir quel temps il va faire. Elle va
retourner un rel indiquant de 0 1 sil va pleuvoir. La tche reoit un String en paramtre (lURL
du serveur), publie rgulirement le pourcentage davancement (un entier) et retourne un Float. Cela
donne cette instanciation du modle gnrique :

121
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

class MyTask extends AsyncTask<String, Integer, Float>

et ses mthodes sont paramtres ainsi :

Float doInBackground(String urlserveur)


void onProgressUpdate(Integer pourcentage)
void onPostExecute(Float pluie)

7.1.7. Paramtres variables


Alors en fait, cest encore plus complexe, car doInBackground reoit non pas un seul, mais un nombre
quelconque de paramtres tous du mme type. La syntaxe Java utilise la notation ... pour
signifier quen fait, cest un tableau de paramtres.

Float doInBackground(String... urlserveur)

a veut dire quon peut appeler la mme mthode de toutes ces manires, le nombre de paramtres
est variable :

doInBackground();
doInBackground("www.meteo.fr");
doInBackground("www.meteo.fr", "www.weather.fr","www.bericht.fr");

Le paramtre urlserveur est quivalent un String[] qui contiendra les paramtres.

7.1.8. Dfinition dune AsyncTask


Il faut driver et instancier la classe gnrique. Pour lexemple, jai dfini un constructeur qui permet
de spcifier une ProgressBar mettre jour pendant le travail.
Par exemple :

private class PrevisionPluie


extends AsyncTask<String, Integer, Float>
{
// ProgressBar mettre jour
private ProgressBar mBarre;

// constructeur, fournir la ProgressBar concerne


PrevisionPluie(ProgressBar barre) {
this.mBarre = barre;
}

7.1.9. AsyncTask, suite


Voici la suite avec la tche de fond et lavancement :

122
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

protected Float doInBackground(String... urlserveur) {


float pluie = 0.0f;
int nbre = urlserveur.length;
for (int i=0; i<nbre; i++) {
... interrogation de urlserveur[i] ...
// faire appeler onProgressUpdate avec le %
publishProgress((int)(i*100.0f/nbre));
}
// a va appeler onPostExecute(pluie)
return pluie;
}

protected void onProgressUpdate(Integer... progress) {


mBarre.setProgress( progress[0] );
}

7.1.10. Lancement dune AsyncTask


Cest trs simple, on cre une instance de cet AsyncTask et on appelle sa mthode execute. Ses
paramtres sont directement fournis doInBackground :

ProgressBar mProgressBar =
(ProgressBar) findViewById(R.id.pourcent);
new PrevisionPluie(mProgressBar)
.execute("www.meteo.fr","www.weather.fr","www.bericht.fr");

execute va crer un thread spar pour effectuer doInBackground, mais les autres mthodes du
AsyncTask restent dans le thread principal.

7.1.11. Schma rcapitulatif

7.1.12. execute ne retourne rien


En revanche, il manque quelque chose pour rcuprer le rsultat une fois le travail termin. Pourquoi
nest-il pas possible de faire ceci ?

float pluie =
new PrevisionPluie(mProgressBar).execute("www.meteo.fr");

Ce nest pas possible car :


1. execute retourne void, donc rien,
2. lexcution de doInBackground nest pas dans le mme thread, or un thread ne peut pas faire
return dans un autre,
3. execute prend du temps et cest justement a quon veut pas.
Solutions : dfinir le thread appelant en tant qucouteur de cet AsyncTask ou faire les traitements
du rsultat dans la mthode onPostExecute.

123
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 42: Mthodes dun AsyncTask

7.1.13. Rcupration du rsultat dun AsyncTask


Pour recevoir le rsultat dun AsyncTask, il faut gnralement mettre en place un couteur qui est
dclench dans la mthode onPostExecute. Exemple :

public interface PrevisionPluieListener {


public void onPrevisionPluieConnue(Float pluie);
}
// couteur = l'activit qui lance l'AsyncTask
private PrevisionPluieListener ecouteur;
// appele quand c'est fini, rveille l'couteur
protected void onPostExecute(Float pluie) {
ecouteur.onPrevisionPluieConnue(pluie);
}

Lcouteur est fourni en paramtre du constructeur, par exemple :


new PrevisionPluie(this, ...).execute(...);

7.1.14. Simplification
On peut simplifier un peu sil ny a pas besoin de ProgressBar et si le rsultat est directement utilis
dans onPostExecute :

private class PrevisionPluie


extends AsyncTask<String, Void, Float> {

protected Float doInBackground(String... urlserveur) {


float pluie = 0.0f;
// interrogation des serveurs
...
return pluie;

124
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

}
protected void onPostExecute(Float pluie) {
// utiliser pluie, ex: l'afficher dans un TextView
...
}
}

7.1.15. Recommandations
Il faut faire extrmement attention :
ne pas bloquer le thread principal dans une callback plus de quelques fractions de secondes,
ne pas manipuler une vue ailleurs que dans le thread principal.
Ce dernier point est trs difficile respecter dans certains cas. Si on cre un thread, il ne doit jamais
accder aux vues de linterface. Un thread na donc aucun moyen direct dinteragir avec lutilisateur.
Si vous tentez quand mme, lexception qui se produit est :
Only the original thread that created a view hierarchy can touch its views
Les solutions dpassent largement le cadre de ce cours et passent par exemple par la mthode
Activity.runOnUiThread

7.1.16. Autres tches asynchrones


Il existe une autre manire de lancer une tche asynchrone :

Handler handler = new Handler();


final Runnable tache = new Runnable() {
@Override
public void run() {
... faire quelque chose ...
// optionnel : relancer cette tche dans 5 secondes
handler.postDelayed(this, 5000);
}
};
// lancer la tche tout de suite
handler.post(tache);

Le handler gre le lancement immdiat (post) ou retard (postDelayed) de la tche. Elle peut
elle-mme se relancer.

7.2. Requtes HTTP


7.2.1. Prsentation
Voici quelques explications sur la manire de faire une requte HTTP dune tablette vers un serveur.
Android propose plusieurs mcanismes :

125
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

un client HTTP Apache DefaultHttpClient bien pratique, mais il est obsolte depuis lAPI
22,
une classe appele HttpURLConnection maintenant recommande,
une API appele Volley un peu trop complexe pour ce cours.
Vous savez que le protocole HTTP a plusieurs mthodes , dont GET, POST, PUT et DELETE qui sont
employes pour grer un WebService. On va voir les deux premires.

7.2.2. Principe de programmation pour un GET


Voici les tapes :
1. Crer une instance de URL qui indique lurl de la page voulue, avec ses paramtres,
2. Crer une instance de HttpURLConnection en appelant openConnection() sur lURL,
3. (optionnel) Configurer la requte : agent, authentification, type mime, session, cookies. . .
4. Lire la rponse avec getInputStream(), intercepter les exceptions IOException sil y a un
problme,
5. Dconnecter afin de librer la connexion.
Noter que le serveur peut mettre du temps rpondre, il faut donc placer cela dans une AsyncTask.

7.2.3. Exemple de requte GET

URL url = new URL("http://SERVEUR/get_avis.php?_id=2");


HttpURLConnection connexion =
(HttpURLConnection) url.openConnection();
connexion.setReadTimeout(10000);
connexion.setRequestProperty("User-Agent", "Mozilla/5.0");
try {
InputStream reponse = connexion.getInputStream();
int code = connexion.getResponseCode();

... utiliser new BufferedInputStream(reponse) ...


} catch (IOException e) {
... mauvais URL, pb rseau ou serveur inactif ...
} finally {
connexion.disconnect();
}

7.2.4. Encodage de paramtres pour une requte


Les paramtres dune requte GET ou POST doivent tre encods (cf wikipedia). Les couples
(nom1,val1), (nom2,val2) deviennent ?nom1=val1&nom2=val2. Dedans, les espaces sont remplacs
par + et les caractres bizarres par leur code UTF8, ex: devient %C3%A9.
Utiliser la mthode URLEncoder.encode(chane, charset) :

126
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

String params =
"?libelle=" + URLEncoder.encode(libelle, "UTF-8") +
"&auteur=" + URLEncoder.encode(auteur, "UTF-8");

Voir le TP7 pour une implantation plus polyvalente (boucle sur un ContentValues).

7.2.5. Principe de programmation pour un POST


Un POST est un peu plus complexe car il faut encoder un corps de requte. Le dbut est similaire
une requte GET, mais ensuite :
1. Configurer en mode POST
2. Fournir un contenu avec getOutputStream(),
3. (optionnel) Lire la rponse avec getInputStream(),
4. Dconnecter afin de librer la connexion.
Le contenu est placer dans le flux dsign par getOutputStream(), mais avant :
soit on connat la taille du contenu ds le dbut :
appeler setFixedLengthStreamingMode(taille);
soit on ne la connat pas (ex: streaming) :
appeler setChunkedStreamingMode(0);

7.2.6. Exemple de requte POST

URL url = new URL("http://SERVEUR/insert_avis.php");


HttpURLConnection connexion = (HUC..) url.openConnection();
try {
connexion.setDoOutput(true);
connexion.setRequestMethod("POST");
String params = "libelle=ok&note=3.5&...";
connexion.setFixedLengthStreamingMode(params.length());
DataOutputStream contenu =
new DataOutputStream(connexion.getOutputStream());
contenu.writeBytes(params);
contenu.close();
... ventuellement utiliser getInputStream ...
} finally {
connexion.disconnect();
}

7.2.7. Requtes asynchones


Comme le serveur peut rpondre avec beaucoup de retard, il faut employer une sous-classe dAsyncTask.
Par exemple ceci :
Constructeur : on lui fournit lURL contacter ainsi que tous les paramtres ncessaires, ils
sont simplement mmoriss dans la classe,

127
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

String doInBackground() : ouvre la connexion, construit et lance la requte, retourne la


rponse du serveur et ferme la connexion,
void onPostExecute(String reponse) : traite la rponse du serveur ou rveille un couteur.

7.2.8. Permissions pour lapplication


Pour finir, il faut rajouter ceci dans le manifeste au mme niveau que lapplication :

<uses-permission android:name="android.permission.INTERNET"/>

Sans cela, les connexions rseau seront systmatiquement refuses.

7.3. OpenStreetMap
7.3.1. Prsentation
Au contraire de Google Maps, OSM est vraiment libre et OpenSource, et il se programme extrmement
facilement.

7.3.2. Documentation
Nous allons utiliser deux librairies :
OSMdroid : cest la librarie de base, super mal documente. Attention ne pas confondre avec
un site de piraterie.
OSMbonusPack, un ajout remarquable cette base. Son auteur sappelle Mathieu Kergall. Il
a ajout de trs nombreuses fonctionalits permettant entre autres dutiliser OpenStreetMap
pour grer des itinraires comme les GPS de voiture et aussi afficher des fichiers KML venant
de Google Earth.
Lire cette suite de tutoriels pour dcouvrir les possibilits de osmbonuspack.

7.3.3. Pour commencer


Il faut dabord installer plusieurs archives jar :
OSMbonusPack. Il est indiqu comment inclure cette librairie et ses dpendances dans votre
projet AndroidStudio. Voir le TP8 partie 2 pour voir comment faire sans connexion rseau.
OSMdroid. Cest la librairie de base pour avoir des cartes OSM.
GSON : cest une librairie pour lire et crire du JSON,
OkHTTP et OKio : deux librairies pour gnrer des requtes HTTP.
Linclusion de librairies est la fois simple et compliqu. La complexit vient de lintgration des
librairies et de leurs dpendances dans un serveur central, maven .

7.3.4. Layout pour une carte OSM


Ce nest pas un fragment, mais une vue personnalise :

128
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 43: 129


Google Maps
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

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


<LinearLayout xmlns:android="..."
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<org.osmdroid.views.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
tilesource="Mapnik"/>
</LinearLayout>

Vous pouvez rajouter ce que vous voulez autour.

7.3.5. Activit pour une carte OSM


Voici la mthode onCreate minimale :

private MapView mMap;

@Override
protected void onCreate(Bundle savedInstanceState)
{
// mise en place de l'interface
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);

// rajouter les contrles utilisateur


mMap = (MapView) findViewById(R.id.map);
mMap.setMultiTouchControls(true);
mMap.setBuiltInZoomControls(true);
}

7.3.6. Positionnement de la vue


Pour modifier la vue initiale de la carte, il faut faire appel au IMapController associ la carte :

// rcuprer le gestionnaire de carte (= camra)


IMapController mapController = mMap.getController();

// dfinir la vue initiale


mapController.setZoom(14);
mapController.setCenter(new GeoPoint(48.745, -3.455));

Un GeoPoint est un couple (latitude, longitude) reprsentant un point sur Terre. Il y a aussi laltitude
si on veut. Cest quivalent un LatLng de GoogleMaps.

130
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

7.3.7. Calques
Les ajouts sur la carte sont faits sur des overlays. Ce sont comme des calques. Pour ajouter quelque
chose, il faut crer un Overlay, lui rajouter des lments et insrer cet overlay sur la carte.
Il existe diffrents types doverlays, p. ex. :
ScaleBarOverlay : rajoute une chelle
ItemizedIconOverlay : rajoute des marqueurs
RoadOverlay, Polyline : rajoute des lignes
Par exemple, pour rajouter un indicateur dchelle de la carte :

// ajouter l'chelle des distances


ScaleBarOverlay echelle = new ScaleBarOverlay(mMap);
mMap.getOverlays().add(echelle);

7.3.8. Mise jour de la carte


Chaque fois quon rajoute quelque chose sur la carte, il est recommand de rafrachir la vue :

// redessiner la carte
mMap.invalidate();

a marche sans cela dans la plupart des cas, mais y penser sil y a un problme.

7.3.9. Marqueurs
Un marqueur est reprsent par un Marker :

Marker mrkIUT = new Marker(mMap);


GeoPoint gpIUT = new GeoPoint(48.75792, -3.4520072);
mrkIUT.setPosition(gpIUT);
mrkIUT.setSnippet("Dpartement INFO, IUT de Lannion");
mrkIUT.setAlpha(0.75f);
mrkIUT.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mMap.getOverlays().add(mrkIUT);

snippet est une description succincte du marqueur,


alpha est la transparence : 1.0=opaque, 0.0=invisible,
anchor dsigne le hot point de limage, le pixel aligner avec la position.

7.3.10. Marqueur personnaliss


Pour changer limage par dfaut (une main dans une poire), il vous suffit de placer une image png
dans res/drawable. Puis charger cette image et lattribuer au marqueur :

Drawable fleche = getResources().getDrawable(R.drawable.fleche);


mrkIUT.setIcon(fleche);
mrkIUT.setAnchor(Marker.ANCHOR_RIGHT, Marker.ANCHOR_BOTTOM);

131
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 44: Marqueur personnalis

7.3.11. Raction un clic


On peut dfinir un couteur pour les clics sur le marqueur :

mrkIUT.setOnMarkerClickListener(new OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker, MapView map)
{
Toast.makeText(MainActivity.this,
marker.getSnippet(),
Toast.LENGTH_LONG).show();
return false;
}
});

Ici, je fais afficher le snippet du marqueur dans un Toast.

7.3.12. Itinraires
Il est trs facile de dessiner un itinraire sur OSM. On donne le GeoPoint de dpart et celui darrive
dans une liste, ventuellement des tapes intermdiaires :

// itinraire pour aller de la gare l'IUT


RoadManager manager = new OSRMRoadManager(this);
ArrayList<GeoPoint> etapes = new ArrayList<GeoPoint>();
etapes.add(gpGare);
etapes.add(gpIUT);
Road route = manager.getRoad(etapes);
// ajouter cette route sur la carte sous les marqueurs
Polyline ligne = RoadManager.buildRoadOverlay(route, this);
mMap.getOverlays().add(0, ligne);

Seul problme : faire cela dans un AsyncTask ! (voir TP8 partie 2)

7.3.13. Position GPS


Un dernier problme : comment lire les coordonnes fournies par le rcepteur GPS ? Il faut faire
appel au LocationManager. Ses mthodes retournent les coordonnes gographiques.

132
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

LocationManager locationManager =
(LocationManager) getSystemService(LOCATION_SERVICE);
Location position =
locationManager.getLastKnownLocation(
LocationManager.GPS_PROVIDER);
if (position != null) {
mapController.setCenter(new GeoPoint(position));
}

NB: a ne marche quen plein air (rception GPS). Consulter aussi cette page propos de lutilisation
du GPS et des rseaux.

7.3.14. Mise jour en temps rel de la position


Si on veut suivre et afficher les mouvements :

locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, this);

On peut utiliser la localisation par Wifi, mettre NETWORK_PROVIDER.


Le dernier paramtre est un couteur, ici this. Il doit implmenter les mthodes de linterface
LocationListener dont :

public void onLocationChanged(Location position)


{
// dplacer le marqueur de l'utilisateur
mrkUti.setPosition(new GeoPoint(position));
// redessiner la carte
mMap.invalidate();
}

7.3.15. Positions simules


Pour tester une application base sur le GPS sans se dplacer physiquement, il y a moyen denvoyer
de fausses positions avec Android Studio.
Il faut afficher la fentre Android Device Monitor par le menu Tools, item Android. Dans longlet
Emulator, il y a un panneau pour dfinir la position de lAVD, soit fixe, soit laide dun fichier GPX
provenant dun rcepteur GPS de randonne par exemple.

7.3.16. Clics sur la carte


Cest le seul point un peu complexe. Il faut sous-classer la classe Overlay afin de rcuprer les
touchers de lcran. On doit seulement intercepter les clics longs pour ne pas gner les mouvements
sur la carte. Voici le dbut :

133
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

public class LongPressMapOverlay extends Overlay {


// constructeur
public LongPressMapOverlay(Context context) {
super(context);
}
@Override
protected void draw(Canvas c, MapView m, boolean shadow)
{}

Pour installer ce mcanisme, il faut rajouter ceci dans onCreate :

mMap.getOverlays().add(new LongPressMapOverlay(this));

7.3.17. Traitement des clics


Le cur de la classe traite les clics longs en convertissant les coordonnes du clic en coordonnes
gographiques :
@Override
public boolean onLongPress(MotionEvent event, MapView map)
{
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Projection projection = map.getProjection();
GeoPoint position = (GeoPoint) projection.fromPixels(
(int)event.getX(), (int)event.getY());
// utiliser position ...
}
return true;
}

Par exemple, elle cre ou dplace un marqueur.

7.3.18. Autorisations
Pour finir, Il faut autoriser plusieurs choses dans le Manifeste : accs au GPS et au rseau, et criture
sur la carte mmoire :
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

134
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

7.3.19. Voil tout pour cette semaine


Cest fini pour cette semaine, rendez-vous la semaine prochaine pour un cours sur le dessin en 2D.

135
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Semaine 8

Dessin 2D interactif

Le cours de cette semaine concerne le dessin de figures 2D et les interactions avec lutilisateur.
CustomView et Canevas
Un exemple de bote de dialogue utile

Figure 45: Application de dessin

8.1. Dessin en 2D
8.1.1. Principes
Une application de dessin 2D dfinit une sous-classe de View et surcharge sa mthode onDraw, cest
elle qui est appele pour dessiner la vue. Voici le squelette minimal :

package fr.iutlan.dessin;
public class DessinView extends View {
Paint mPeinture;
public DessinView(Context context, AttributeSet attrs) {
super(context, attrs);
mPeinture = new Paint();

136
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

mPeinture.setColor(Color.BLUE);
}
public void onDraw(Canvas canvas) {
canvas.drawCircle(100, 100, 50, mPeinture);
}
}

8.1.2. Layout pour le dessin


Pour voir DessinView, il faut linclure dans un layout :

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


<LinearLayout xmlns:android="..."
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fr.iutlan.dessin.DessinView
android:id="@+id/dessin"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

Il faut mettre le package et le nom de la classe en tant que balise XML. Ne pas oublier les attributs
de taille.

8.1.3. Mthode onDraw


La mthode onDraw(Canvas canvas) doit effectuer tous les tracs. Cette mthode doit tre rapide.
galement, elle ne doit faire aucun new. Il faut donc crer tous les objets ncessaires auparavant, par
exemple dans le constructeur de la vue.
Son paramtre canvas reprsente la zone de dessin. Attention, ce nest pas un bitmap. Un canvas
ne possde pas de pixels ; cest le bitmap associ la vue qui les possde. Voici comment on associe
un canvas un bitmap :

Bitmap bm =
Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bm);

Cest dj fait pour le canvas fourni la mthode onDraw. On obtient le bitmap de la vue avec
getDrawingCache().

8.1.4. Mthodes de la classe Canvas


La classe Canvas possde de nombreuses mthodes de dessin :
drawColor(int color) : efface le canvas avec la couleur indique. Cette couleur est un code
32 bits retourn par la classe statique Color :

137
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Color.BLACK, Color.RED. . . : couleurs prdfinies,


Color.rgb(int r, int v, int b) : convertit des composantes RVB 0..255 en un code
de couleur.
drawLine (float x1, float y1, float x2, float y2, Paint peinture) : trace une
ligne entre (x1,y1) et (x2,y2) avec la peinture
drawCircle (float cx, float cy, float rayon, Paint paint) dessine un cercle.
etc.

8.1.5. Peinture Paint


Cette classe permet de reprsenter les modes de dessin : couleurs de trac, de remplissage, polices,
lissage. . . Cest extrmement riche. Voici un exemple dutilisation :
mPeinture = new Paint(Paint.ANTI_ALIAS_FLAG);
mPeinture.setColor(Color.rgb(128, 255, 32));
mPeinture.setAlpha(192);
mPeinture.setStyle(Paint.Style.STROKE);
mPeinture.setStrokeWidth(10);

Il est prfrable de crer les peintures dans le constructeur de la vue ou une autre mthode, mais
surtout pas dans la mthode onDraw.

8.1.6. Quelques accesseurs de Paint


Parmi la liste de ce qui existe, on peut citer :
setColor(Color), setARGB(int a, int r, int v, int b), setAlpha(int a) : dfinissent
la couleur et la transparence de la peinture,
setStyle(Paint.Style style) : indique ce quil faut dessiner pour une forme telle quun
rectangle ou un cercle :
Paint.Style.STROKE uniquement le contour
Paint.Style.FILL uniquement lintrieur
Paint.Style.FILL_AND_STROKE contour et intrieur
setStrokeWidth(float pixels) dfinit la largeur du contour.

8.1.7. Motifs
Il est possible de crer une peinture base sur un motif. On part dune image motif.png dans le
dossier res/drawable quon emploie comme ceci :
Bitmap bmMotif = BitmapFactory.decodeResource(
context.getResources(), R.drawable.motif);
BitmapShader shaderMotif = new BitmapShader(bmMotif,
Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
mPaintMotif = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintMotif.setShader(shaderMotif);
mPaintMotif.setStyle(Paint.Style.FILL_AND_STROKE);

Cette peinture fait appel un Shader. Cest une classe permettant dappliquer des effets progressifs,
tels quun dgrad ou un motif comme ici (BitmapShader).

138
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

8.1.8. Shaders
Voici la ralisation dun dgrad horizontal bas sur 3 couleurs :

final int[] couleurs = new int[] {


Color.rgb(128, 255, 32), // vert pomme
Color.rgb(255, 128, 32), // orange
Color.rgb(0, 0, 255) // bleu
};
final float[] positions = new float[] { 0.0f, 0.5f, 1.0f };
Shader shader = new LinearGradient(0, 0, 100, 0,
couleurs, positions, Shader.TileMode.CLAMP);
mPaintDegrade = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintDegrade.setShader(shader);

Figure 46: Dgrad horizontal

8.1.9. Shaders, suite et fin


Le dgrad prcdent est base sur trois couleurs situes aux extrmits et au centre du rectangle.
On fournit donc deux tableaux, lun pour les couleurs et lautre pour les positions des couleurs
relativement au dgrad, de 0.0 1.0.
Le dgrad possde une dimension, 100 pixels de large. Si la figure dessiner est plus large, la couleur
sera maintenue constante avec loption CLAMP. Dautres options permettent de faire un effet miroir,
MIRROR, ou redmarrer au dbut REPEAT.
Cette page prsente les shaders et filtres dune manire extrmement intressante. Comme vous
verrez, il y a un grand nombre de possibilits.

8.1.10. Quelques remarques


Lorsquil faut redessiner la vue, appelez invalidate. Si la demande de raffichage est faite dans un
autre thread, alors il doit appeler postInvalidate.
La technique montre dans ce cours convient aux dessins relativement statiques, mais pas un jeu
par exemple. Pour mieux animer le dessin, il est recommand de sous-classer SurfaceView plutt
que View. Les dessins sont alors faits dans un thread spar et dclenchs par des vnements.

8.1.11. Dessinables
Les canvas servent dessiner des figures gomtriques, rectangles, lignes, etc, mais aussi des Drawable,
cest dire des choses dessinables telles que des images bitmap ou des formes quelconques. Il
existe beaucoup de sous-classes de Drawable.
Un Drawable est cr :

139
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

par une image PNG ou JPG dans res/drawable...

Bitmap bm = BitmapFactory
.decodeResource(getResources(), R.drawable.image);
Drawable d = new BitmapDrawable(getResources(),bm);

Android a dfini une norme pour des images PNG tirables, les 9patch .

8.1.12. Images PNG tirables 9patch


Il sagit dimages PNG nommes en .9.png qui peuvent tre dessines de diffrentes tailles. gauche,
limage dorigine et droite, 3 exemplaires tirs.

Figure 47: Image tirable

Une image 9patch est borde sur ses 4 cts par des lignes noires qui spcifient les zones tirables
en haut et gauche, et les zones qui peuvent tre occupes par du texte droite et en bas.
Il faut utiliser loutil draw9patch pour les diter. a demande un peu de savoir-faire.

8.1.13. Drawable, suite


Un drawable peut galement provenir dune forme vectorielle dans un fichier XML. Exemple :
res/drawable/carre.xml :

<?xml version="1.0" encoding="UTF-8"?>


<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="4dp" android:color="#F000" />
<gradient android:angle="90"
android:startColor="#FFBB"
android:endColor="#F77B" />
<corners android:radius="16dp" />
</shape>

Figure 48: Dessin vectoriel XML

140
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

8.1.14. Variantes
Android permet de crer des dessinables variantes par exemple pour des boutons personnaliss.

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


<selector xmlns:android="...">

<item android:drawable="@drawable/button_pressed"
android:state_pressed="true" />
<item android:drawable="@drawable/button_checked"
android:state_checked="true" />
<item android:drawable="@drawable/button_default" />

</selector>

Lune ou lautre des images sera choisie en fonction de ltat du bouton, enfonc, relch, inactif.

8.1.15. Utilisation dun Drawable


Ces objets dessinable peuvent tre employs dans un canvas. Puisque ce sont des objets vectoriels, il
faut dfinir les coordonnes des coins haut-gauche et bas-droit, ce qui permet dtirer la figure. Les
tailles qui sont indiques dans le xml sont pourtant absolues.

Drawable drw = getResources().getDrawable(R.drawable.carre);


drw.setBounds(x1, y1, x2, y2); // coins
drw.draw(canvas);

Remarquez le petit pige de la dernire instruction, on passe le canvas en paramtre la mthode


draw du drawable.
NB: la premire instruction est placer dans le constructeur de la vue, afin de ne pas ralentir la
fonction de dessin.

8.1.16. Enregistrer un dessin dans un fichier


Cest trs facile. Il suffit de rcuprer le bitmap associ la vue, puis de le compresser en PNG.

public void save(String filename)


{
Bitmap bitmap = getDrawingCache();
try {
FileOutputStream out = new FileOutputStream(filename);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
} catch (Exception e) {
...
}
}

141
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

8.1.17. Coordonnes dans un canvas


Un dernier mot sur les canvas. Il y a tout un mcanisme permettant de modifier les coordonnes
dans un canvas :
dplacer lorigine avec translate(dx,dy) : toutes les coordonnes fournies ultrieurement
seront additionnes (dx,dy)
multiplier les coordonnes par sx,sy avec scale(sx,sy)
pivoter les coordonnes autour de (px,py) dun angle ao avec rotate(a, px, py)
En fait, il y a un mcanisme de transformations matricielles 2D appliques aux coordonnes, ainsi
quune pile permettant de sauver la transformation actuelle ou la restituer.
save() : enregistre la matrice actuelle
restore() : restitue la matrice avec celle qui avait t sauve

8.2. Interactions avec lutilisateur


8.2.1. couteurs pour les touchers de lcran
Il existe beaucoup dcouteurs pour les actions de lutilisateur sur une zone de dessin. Parmi elles, on
doit connatre onTouchEvent. Son paramtre indique la nature de laction (toucher, mouvement. . . )
ainsi que les coordonnes.

@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();

switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
...
break;
}
return true;
}

8.2.2. Modle de gestion des actions


Souvent il faut distinguer le premier toucher (ex: cration dune figure) des mouvements suivants (ex:
taille de la figure).

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
figure = Figure.creer(typefigure, color);
figure.setReference(x, y);
figures.add(figure);
break;
case MotionEvent.ACTION_MOVE:

142
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

if (figures.size() < 1) return true;


figure = figures.getLast();
figure.setCoin(x,y);
break;
}
invalidate();

8.2.3. Automate pour grer les actions


Lalgo prcdent peut se reprsenter laide dun automate de Mealy deux tats : repos et en cours
ddition dune figure. Les changements dtats sont dclenchs par les actions utilisateur et effectuent
un traitement.

Figure 49: Automate

8.3. Botes de dialogue spcifiques


8.3.1. Slecteur de couleur
Android ne propose pas de slecteur de couleur, alors il faut le construire soi-mme.

Figure 50: Slecteur de couleur

8.3.2. Version simple


En TP, on va construire une version simplifie afin de comprendre le principe :

143
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 51: Slecteur de couleur simple

8.3.3. Concepts
Plusieurs concepts interviennent dans ce slecteur de couleur :
La fentre drive de DialogFragment, elle affiche un dialogue de type AlertDialog avec des
boutons Ok et Annuler,
Cet AlertDialog contient une vue personnalise contenant des SeekBar pour rgler les com-
posantes de couleur,
Les SeekBar du layout ont des callbacks qui mettent jour la couleur choisie en temps rel,
Le bouton Valider du AlertDialog dclenche un couteur dans lactivit qui a appel le slecteur.

8.3.4. Fragment de dialogue


Le fragment de dialogue doit dfinir plusieurs choses :
Cest une sous-classe de FragmentDialog

public class ColorPickerDialog extends DialogFragment

Il dfinit une interface pour un couteur quil appellera la fin :

public interface OnColorChangedListener {


void colorChanged(int color);
}

Une mthode onCreateDialog retourne un AlertDialog pour bnficier des boutons ok et


annuler. Le bouton ok est associ une callback qui active lcouteur en lui fournissant la
couleur.

8.3.5. Mthode onCreateDialog

public Dialog onCreateDialog(Bundle savedInstanceState) {


Context ctx = getActivity();
Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle("Choisissez une couleur");

144
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

final ColorPickerView cpv = new ColorPickerView(ctx);


builder.setView(cpv);
builder.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int btn) {
// prvenir l'couteur
mListener.colorChanged(cpv.getColor());
}
});
builder.setNegativeButton(android.R.string.no, null);
return builder.create();
}

8.3.6. Vue personnalise dans le dialogue


Voici la dfinition de la classe ColorPickerView qui est lintrieur du dialogue dalerte. Elle gre
quatre curseurs et une couleur :
private static class ColorPickerView extends LinearLayout {
// couleur dfinie par les curseurs
private int mColor;
// constructeur
ColorPickerView(Context context) {
// constructeur de la superclasse
super(context);
// mettre en place le layout
inflate(getContext(), R.layout.colorpickerdialog, this);
...
}

8.3.7. Layout de cette vue


Le layout colorpickerdialog.xml contient quatre SeekBar, rouge, vert, bleu et alpha. Ils ont une
callback comme celle-ci :
SeekBar sbRouge = (SeekBar) findViewById(R.id.sbRouge);
sbRouge.setOnSeekBarChangeListener(
new OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekBar,
int progress, boolean fromUser) {
mColor = Color.argb(
Color.alpha(mColor), progress,
Color.green(mColor), Color.blue(mColor));
}
});

Elle change seulement la composante rouge de la variable mColor. Il y a les mmes choses pour le
vert, le bleu et la transparence.

145
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

8.3.8. Utilisation du dialogue


Pour finir, voici comment on affiche ce dialogue, par exemple dans un menu :

new ColorPickerDialog(
new ColorPickerDialog.OnColorChangedListener() {
@Override
public void colorChanged(int color) {
// utiliser la couleur ....
}
}
).show(getFragmentManager(), "fragment_colorpicker");

Cela consiste dfinir un couteur qui reoit la nouvelle couleur du slecteur. Lcouteur peut la
transmettre la classe qui dessine une nouvelle figure.

8.3.9. Slecteur de fichier


Dans le mme genre mais nettement trop complexe, il y a le slecteur de fichiers pour enregistrer un
dessin.

8.3.10. Cest la fin


Cest fini, nous avons tudi tout ce quil tait raisonnable de faire en 8 semaines.

146
IUT de Lannion P. Nerzic
Dept Informatique Programmation Android 2016-17

Figure 52: Slecteur de fichier

147