Documente Academic
Documente Profesional
Documente Cultură
1.1
Introduction ...............................................................................................................................14
1.3.11
1.3.12
1.3.13
1.3.14
Reconstruction du projet..........................................................................................26
1.4
INNOV MAROC
Page 2
1.5
1.6.1 Paquet 32
1.6.2 Signature dune application .................................................................................................32
1.6.3 Cration du keystore ..............................................................................................................32
1.6.4 Cration dune cl ....................................................................................................................32
1.6.5 Cration du paquet ...............................................................................................................32
2
2.1
2.1.11
Identifiants et vues.....................................................................................................38
2.1.12
2.1.13
2.1.14
2.1.15
Autres ............................................................................................................................40
2.2
Dispositions ...............................................................................................................................40
INNOV MAROC
Page 3
2.2.11
2.2.12
2.2.13
2.2.14
2.2.15
Autres groupements..................................................................................................45
2.3
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
3.1
INNOV MAROC
Page 4
Applications ..............................................................................................................................51
3.2.11
3.2.12
3.2.13
3.3
Activits ......................................................................................................................................55
INNOV MAROC
Page 5
4.1
Prsentation ...............................................................................................................................62
Adaptateurs ...............................................................................................................................68
INNOV MAROC
Page 6
4.4.11
4.4.12
4.4.13
Rcapitulatif .................................................................................................................74
4.4.14
Le rsultat .....................................................................................................................74
4.5
Ergonomie ..................................................................................................................................79
5.1
5.1.11
5.1.12
5.2
INNOV MAROC
Page 7
5.3.11
FragmentManager .....................................................................................................90
5.3.12
5.3.13
5.3.14
5.3.15
5.3.16
5.3.17
5.3.18
5.3.19
5.3.20
5.3.21
5.4
INNOV MAROC
Page 8
6.1
SQLite3 ........................................................................................................................................98
6.2.11
6.2.12
6.2.13
6.2.14
6.2.15
6.2.16
6.2.17
6.2.18
6.2.19
6.2.20
6.2.21
6.2.22
INNOV MAROC
Page 9
6.2.23
6.2.24
6.2.25
6.2.26
6.3
ContentProviders ...................................................................................................................111
WebServices .............................................................................................................................112
6.5.11
6.5.12
7.1
AsyncTasks ..............................................................................................................................116
INNOV MAROC
Page 10
7.1.11
Schma rcapitulatif.................................................................................................119
7.1.12
7.1.13
7.1.14
Simplification .............................................................................................................120
7.1.15
Recommandations ....................................................................................................121
7.1.16
7.2
OpenStreetMap .......................................................................................................................124
7.3.11
7.3.12
Itinraires ....................................................................................................................128
7.3.13
INNOV MAROC
Page 11
7.3.14
Autorisations ..............................................................................................................129
7.3.15
7.3.16
7.3.17
7.3.18
8.1
Dessin en 2D ............................................................................................................................131
8.1.1 Principes....................................................................................................................................131
8.1.2 Layout pour le dessin ............................................................................................................132
8.1.3 Mthode onDraw ...................................................................................................................132
8.1.4 Mthodes de la classe Canvas.............................................................................................132
8.1.5 Peinture Paint ..........................................................................................................................133
8.1.6 Quelques accesseurs de Paint ..........................................................................................133
8.1.7 Motifs 133
8.1.8 Shaders ......................................................................................................................................134
8.1.9 Shaders, suite et fin ................................................................................................................134
8.1.10
8.1.11
Dessinables ...........................................................................................................134
8.1.12
8.1.13
8.1.14
Variantes .....................................................................................................................136
8.1.15
8.1.16
8.1.17
8.2
INNOV MAROC
Page 12
INNOV MAROC
Page 13
Environnement de dveloppement
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 6.
1.1.2
Dfinition
INNOV MAROC
Page 14
INNOV MAROC
Page 15
1.1.3
Composants dAndroid
1.1.4
Programmation dapplications
Application Android :
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. Avant, on pouvait utiliser Eclipse, mais son plugin Android nest plus dvelopp.
1.2
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.
1.2.3
INNOV MAROC
Page 16
1.2.4
Dossiers du SDK
1.2.5
Android Studio
Pour finir, il faut installer Android Studio selon la procdure explique ci aprs.
INNOV MAROC
Page 17
INNOV MAROC
Page 18
INNOV MAROC
Page 19
INNOV MAROC
Page 20
INNOV MAROC
Page 21
INNOV MAROC
Page 22
INNOV MAROC
Page 23
INNOV MAROC
Page 24
INNOV MAROC
Page 25
INNOV MAROC
Page 26
INNOV MAROC
Page 27
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.
1.3
Premire application
1.3.1 Objectifs
1.3.2
1.3.3
Choix de la version
Chaque version dAndroid, dnote par son API level, 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
1.3.5
Ensuite, on choisit le type de projet. Pour un premier essai, on se limite au plus simple, Blank
Activity :
Voir la figure 5.
INNOV MAROC
Page 28
INNOV MAROC
Page 29
INNOV MAROC
Page 30
INNOV MAROC
Page 31
1.3.6
Points configurer
1.3.7
1.3.8
Rsultat de lassistant
1.3.9
Fentre du projet
Voir la figure 7.
1.3.10 diteurs
spcifiques
Studio fournit des diteurs spcialiss pour les fichiers XML, par exemple :
Formulaires pour :
res/values/strings.xml : textes de linterface.
diteurs graphiques pour :
res/layout/*.xml : disposition des contrles sur linterface.
1.3.11 Exemple
res/values/strings.xml
Voir la figure 8.
INNOV MAROC
Page 32
INNOV MAROC
Page 33
Figure 7: lments2d
4un projet Android
25
1.3.12 Exemple
res/layout/main.xml
Voir la figure 9.
1.3.13 Source
XML sous-jacent
Ces diteurs sont plus confortables que le XML brut, mais ne permettent pas de tout faire.
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>
1.3.14 Reconstruction
du projet
Automatique :
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...
1.4
Premire excution
1.4.1 Excution de lapplication
27
1.4.4
1.5
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
28
29
1.5.3
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
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
30
1.5.7
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
1.5.9
31
. . . enfin en
1.6
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
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 :
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.
Cration du keystore
1.6.4 Cration dune cl
1.6.5 Cration du paquet
1.6.3
32
33
34
2.1
Interface et ressources
2.1.1 Activits
Linterface utilisateur dune application Android est compose dcrans. Un cran correspond une
activit, ex :
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 :
une action de lutilisateur, bouton, menu ou lapplication fait aller sur lcran suivant
le bouton back ramne sur lcran prcdent.
2.1.2
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);
35
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
2.1.4
La classe R
Cette classe R est gnre automatiquement par ce que vous mettez dans le dossier res : dispositions,
identifiants, chanes. . . Les dispositions et autres sont dfinies par des fichiers XML.
Par exemple, res/values/strings.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Exemple</string>
<string name="message">Bonjour !</string>
<resources>
2.1.5
</element>
texte en vrac
</racine>
2.1.6
Dans le cas dAndroid, il y a un grand nombre dlments et dattributs normaliss. Les attributs ont
t regroups dans un namespace (xmlns). Leur nom est android:nomattribut.
Vous pouvez lire cette page 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
Il est possible de crer une interface par programme, mais cest assez compliqu :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context ctx = getApplicationContext();
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
37
2.1.9
2.1.10 Rfrencement
2.1.11 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);
(remarquez la conversion de type), avec la dfinition suivante :
38
<RelativeLayout>
<TextView android:id="@+id/message"
android:text="@string/bonjour"
/>
</RelativeLayout>
La notation @+id/nom fait crer ou utiliser R.id.nom.
2.1.12 android:id
= @id/nom ou @+id/nom
2.1.13 Images
: R.drawable.nom
/>
2.1.14 Tableau
de chanes : R.array.nom
39
2.1.15 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
2.2.3
Reprsentation en XML
40
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
2.2.6
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
2.2.9
Une faon intressante de spcifier les tailles des vues dans un LinearLayout consiste leur affecter
un poids avec lattribut android:layout_weight.
42
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
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>
.../>
.../>
.../>
.../>
43
2.2.12 Largeur
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.
44
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
2.3.2
TextView
<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
2.3.4
Bascules
android:textOn et android:textOff.
2.3.5
EditText
<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 ultrieurement, pour prciser les attributs utiles pour une
application. Dautres vues pourront aussi tre employes loccasion.
2.4
Styles
2.4.1 Styles et thmes
2.4.2
Dfinir un style
46
2.4.3
Utiliser un style
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.
.
47
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, ,
des rcepteurs dannonces : pour grer des vnements globaux envoys par le systme toutes
les applications.
3.1.2
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>.
48
3.1.3
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
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
49
3.1.6
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
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
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
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",
50
"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
3.2.3
3.2.4
Le lancement dune activit avec attente de rsultat est plus complexe. Il faut dfinir un code dappel
RequestCode fourni au lancement.
51
52
3.2.5
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
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
53
3.2.8
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 srialisable : nombres, chanes et structures simples.
3.2.9
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
54
3.2.12 Dfinition
3.2.13 Dfinition
3.3
Activits
3.3.1 Prsentation
3.3.2
3.3.3
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
56
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override signifie que cette mthode remplace celle hrite de la superclasse. Il faut quand mme
lappeler sur super en premier.
3.3.5
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
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
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 :
57
3.3.8
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
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.
58
3.4.2
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
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 :
59
btn.setOnClickListener(ecouteur);
3.4.5
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
3.4.8
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
61
Application liste
Durant les prochaines parties, nous allons nous intresser aux applications de gestion dune liste
ditems.
Stockage dune liste
Affichage dune liste, adaptateurs
Consultation et dition dun item
4.1
Prsentation
4.1.1 Principe gnral
On veut programmer une application pour afficher et diter une liste ditems.
Dans cette partie, la liste est stocke dans un tableau dynamique appel ArrayList ;
Ultrieurement, a sera dans une base de donnes SQL locale ou sur un serveur distant.
62
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.
4.1.3
4.1.4
Donnes initiales
4.1.5
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
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.
64
4.1.7
4.1.8
4.1.9
Remarques
Dans cette partie, 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 auparavant et mettre ce tableau ainsi que son initialisation dedans. Ainsi, le tableau devient
disponible dans toutes les activits de lapplication. Voir le TP4.
Ultrieurement, 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 :
65
66
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
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
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
// initialisation de la liste
mListe = new ArrayList<Planete>();
...
4.2.5
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.
4.2.7
Layouts prdfinis
4.3
Adaptateurs
4.3.1 Relations entre la vue et les donnes
4.3.2
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
4.3.4
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)
68
4.3.5
Exemple demploi
4.3.6
4.3.7
69
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
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.
70
4.4.3
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
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 :
71
package fr.iutlan.planetes;
public class PlaneteView extends RelativeLayout
{
...
4.4.6
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
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
4.4.9
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) findViewById(
73
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
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 :
74
4.5.2
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.
adapter.notifyDataSetChanged(); au retour.
4.5.3
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,
75
4.5.4
4.5.5
4.5.6
4.5.7
76
4.5.8
4.5.9
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).
77
78
Ergonomie
5.1
La barre daction contient licne dapplication (1), quelques items de menu (2) et un bouton pour
avoir les autres (3).
5.1.2
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. Doc Android sur la barre daction et sur les
menus
Il faut dfinir :
un fichier res/menu/nom_du_menu.xml,
des thmes pour afficher soit la barre daction, soit des menus,
deux callbacks pour grer les menus : cration et activation.
79
5.1.3
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
Android distribue gratuitement un grand jeu dicnes pour les menus, dans les deux styles : HoloDark
et HoloLight.
5.1.5
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 :
80
<resources>
<style name="AppBaseTheme"
parent="android:Theme.Holo.Light"
</resources>
/>
5.1.6
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
5.1.8
Menus en cascade
81
5.1.9
Menus contextuels
5.1.10 Associer
82
lv.setOnCreateContextMenuListener(this);
5.1.11 Callback
daffichage du menu
5.1.12 Callback
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 :
83
5.2.2
Annonces personnalises
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.
84
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 :
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
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
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.
85
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.
5.2.8
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) {
dialog.dismiss();
// fermer le dialogue
...
}
});
// afficher le dialogue
dialog.show();
86
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.
5.3.3
Un fragment est une activit trs simplifie. Cest seulement un arbre de vue dfini par un layout, et
des couteurs. Un fragment minimal est :
87
5.3.4
5.3.5
Les fragments ont un cycle de vie similaire celui des activits, avec quelques mthodes de plus
correspondant leur intgration dans une activit.
5.3.6
ListFragment
@Override
setHasOptionsMenu(true);
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);
89
5.3.9
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
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
En trois temps : obtention du manager, cration dune transaction et attribution des fragments aux
rceptacles .
90
// 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
Le plus intressant est de faire apparatre les fragments en fonction de la taille et lorientation de
lcran (application liste + infos ).
5.3.14 Changer
91
<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
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 :
92
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
5.3.20 Relation
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
5.4.3
5.4.4
Explications
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
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
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 :
// PLANTE
nbmax =
5.4.7
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);
96
editor.putInt("prefs_nbmax", 20);
// fin de la transaction
editor.commit();
5.4.8
5.4.9
97
Aprs avoir reprsent une liste ditems sous forme dun tableau, nous allons la stocker dans un
SGBD SQL.
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. On peut le
lancer partir de bash :
bash$ sqlite3 test.db
sqlite> CREATE TABLE Planetes (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
nom TEXT NOT NULL,
distance REAL,
idType INTEGER NOT NULL,
FOREIGN KEY(idType) REFERENCES Types(_id));
sqlite> INSERT INTO Planetes VALUES (1, "Sedna", 3.5, 1);
6.1.2
SQLite3
SQLite3 est un vrai SGBD relationnel SQL, mais simplifi pour tenir sur une tablette.
Ce qui lui manque :
98
6.1.3
Exemples SQL
6.1.4
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 est aussi une API pour diffrents langages de programmation : C, Python, PHP, Java. . . On
peut excuter des requtes SQL en appelant des fonctions.
Android le propose aux programmeurs pour stocker des informations structures, plutt que bricoler
avec des fichiers. Il est assez facile utiliser une fois le cadre mis en place.
6.1.5
sqlite3 est une commande qui ouvre un shell SQL, pour saisir directement des requtes, sans
connexion. On peut fournir un paramtre, le nom dun fichier qui contient la base, soit aucun et dans
ce cas, la base nest quen mmoire, perdue quand on quitte.
bash$ sqlite3 test.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.
6.1.6
Commandes internes
.dump table affiche le contenu de la table ou de toute la base si la table est omise
.schema table affiche la structure de la table
.headers mettre on ou off pour crire les noms des colonnes en tte de tous les select
.exit sort du shell sqlite3
6.2
Chaque application peut crer une base de donnes. Cest un fichier *.db plac dans le dossier
/data/data/PAQUETAGE /databases/NOM_BDD
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
6.2.3
Principes
100
6.2.4
Si vous ouvrez la base pour toute la vie de lactivit dans onCreate, alors vous devez 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
Recommandations
Il est prfrable 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.
Des mthodes comme find permettent de rcuprer des n-uplets et des mthodes permettent la mise
jour de la base : new, save et delete.
Voir le projet ActiveAndroid pour une implantation Android.
6.2.6
101
6.2.7
6.2.8
Exemples de mthodes
6.2.9
Mthodes SQLiteDatabase.execSQL
Cette mthode excute une requte SQL qui ne retourne pas dinformations : CREATE, INSERT. . .
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.
102
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
6.2.12 Mthodes
update et delete
103
6.2.13 Mthode
rawQuery
Cette mthode, rawQuery permet dexcuter des requtes de type SELECT (pas de ; la fin). 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...");
6.2.14 rawQuery
Sil ny a quun seul n-uplet dans la rponse, il nest pas ncessaire de faire une boucle, mais il faut
quand mme initialiser puis fermer le curseur :
Cursor cursor = bdd.rawQuery("SELECT * FROM table WHERE...");
try {
if (cursor.moveToFirst()) {
// obligatoire
/** utiliser le curseur... **/
}
} finally {
if (cursor != null) cursor.close();
}
6.2.15 Classe
Cursor
6.2.16 Exemple
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 109.
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.
6.2.18 Mthodes
query
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 :
105
String dbpath =
this.getFilesDir().getPath().concat("/test.db");
SQLiteDatabase bdd =
SQLiteDatabase.openOrCreateDatabase(dbpath,
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 105 pour la vritable faon de
faire.
6.2.20 Premire
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
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
Android propose la classe supplmentaire SQLiteOpenHelper qui facilite la gestion des bases de
donnes. Cette classe est une sorte dcouteur avec deux mthodes surcharger :
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...
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... ou carrment DROP TABLE... suivis de onCreate.
Les mthodes getReadableDatabase et getWritableDatabase de SQLiteOpenHelper ouvrent la
base et appellent automatiquement onCreate et onUpgrade si ncessaire.
6.2.22 Exemple
de helper
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);
}
}
6.2.24 mthode
onUpgrade
107
6.2.25 mthode
onUpgrade, suite
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 :
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.
108
6.3.2
tapes suivre
6.3.3
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);
setContentView(R.layout.main);
...
6.3.4
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[]{"_id", "nom"},
// identifiants des TextView qui affichent les colonnes
109
6.3.5
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_ID = 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_ID, null, this);
Cette dernire instruction exige de dfinir trois callbacks dans lactivit :
onLoadFinished et onLoaderReset. Voyons dabord la premire.
6.3.6
onCreateLoader,
6.3.7
classe MonCursorLoader
110
@Override
protected Cursor onLoadInBackground() {
return TablePlanetes.getAll(bdd);
}
Voir page 104 pour la mthode getAll, elle fait seulement return bdd.rawQuery("SELECT * FROM
Planetes", null);
6.3.8
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
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 :
// le chargeur doit recommencer son travail
getLoaderManager().restartLoader(LOADER_ID, null, this);
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.
111
6.5
WebServices
6.5.1 Echange entre un serveur SQL et une application
Android
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. . .
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 HTTP3 :
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.
6.5.2
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.3
112
6.5.4
6.5.5
Cest un format pour transporter des tableaux et des objets travers le rseau. Ils sont crits sous
forme dun texte. JSON est une alternative au XML.
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.6
JSON en Java
En Java, cest 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 = ...;
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. . .
113
6.5.7
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"/>
6.5.8
Il suffit de reprogrammer la mthode getAll de la classe TablePlanetes, voir page 104 et 112 :
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.9
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 ultrieurement.
6.5.10 Modification
dun n-uplet
114
6.5.11 Script
update_planete.php
6.5.12 Mthode
Cette mthode 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 .
Le principe pour cela est de crer une AsyncTask. Elle gre une action qui est excute dans un autre
thread que celui de linterface..
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.
.
115
Cette partie 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).
7.1.2
Tches asynchrones
116
7.1.3
7.1.4
7.1.5
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 :
117
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
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
118
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.
119
7.1.13 Rcupration
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;
120
}
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
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 :
121
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
7.2.3
7.2.4
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) :
122
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
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.
2.
3.
4.
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
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,
123
7.2.8
Pour finir, il faut rajouter ceci dans le manifeste au mme niveau que lapplication :
<uses-permission
android:name="android.permission.INTERNET"/>
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
7.3.3
Pour commencer
7.3.4
124
Figure 42: 1G
25oogle Maps
7.3.5
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.
126
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
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
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);
127
7.3.11 Raction
un clic
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.
128
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 Autorisations
Il faut aussi autoriser laccs au GPS dans le Manifeste, en plus des accs au rseau et lcriture 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"
/>
7.3.15 Mise
7.3.16 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.17 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 :
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
7.3.18 Traitement
LongPressMapOverlay(this));
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.
130
Dessin 2D interactif
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();
131
mPeinture.setColor(Color.BLUE);
}
public void onDraw(Canvas canvas) {
canvas.drawCircle(100, 100, 50, mPeinture);
}
}
8.1.2
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
132
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
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).
133
8.1.8
Shaders
8.1.9
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 :
134
8.1.12 Images
Il sagit dimages PNG nommes en .9.png qui peuvent tre dessines de diffrentes tailles. gauche,
limage dorigine et droite, 3 exemplaires tirs.
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>
135
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
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) {
...
}
}
136
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
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
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:
137
}
invalidate();
8.2.3
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.
8.3
8.3.2
Version simple
8.3.3
Concepts
8.3.4
Fragment de dialogue
8.3.5
Mthode onCreateDialog
139
8.3.6
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
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.
140
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.
141
142