antislashn.org Android - Objectifs 0 - 2/7
Objectifs
● Présenter la plateforme Android● Utiliser l'environnement de développement Android
avec Eclipse● Présenter les composants d'une application
Android● Créer une application Android● Présenter certaines fonctionnalités avancées de la
plateforme Android
antislashn.org Android - Objectifs 0 - 3/7
Chapitres
1.Présentation de la plateforme2.Les outils de développement3."Hello, world" expliqué4.Architecture et développement d'une application5.Composants graphiques de base6.Les intentions7.Les activités8.ListView9.Autres composants graphiques10.Les menus
antislashn.org Android - Objectifs 0 - 4/7
Chapitres
11.Les notifications12.Persistance de données13.Les services14.Les fournisseurs de contenu15.Le BroadcastReceiver16.Les processus et threads17.Les applications widgets18.Les fragments19.Graphisme20.Gestion de équipements21.Géolocalisation et Google Map
antislashn.org Android - Objectifs 0 - 5/7
Annexes
A.Publier avec Google PlayB.Développer en code natif : le NDKC.Input Method EditorD.Persistance avec OrmLite
antislashn.org Android - Objectifs 0 - 6/7
copyleft
Support de formation créé parFranck SIMON
http://www.franck-simon.com
antislashn.org Android - Objectifs 0 - 7/7
copyleft
Cette œuvre est mise à disposition sous licence Attribution
Pas d'Utilisation Commerciale Partage dans les Mêmes Conditions 3.0 France.
Pour voir une copie de cette licence, visitez http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
ou écrivez à Creative Commons, 444 Castro Street, Suite 900,
Mountain View, California, 94041, USA.
antislashn.org Android - Présentation de la plateforme 1 - 1/15
Présentation de la plateformeAndroid
antislashn.org Android - Présentation de la plateforme 1 - 3/15
Généralités
● Android est issu du travail d'une startup● racheté par Google en 2005
● Création le 7 Novembre 2007 de l'OHA● Open Handset Alliance● consortium créé par Google réunissant des acteurs du
marché de la mobilité– constructeurs, opérateurs en téléphonie, éditeurs de logiciels
● annonce officielle de la plateforme Android le même jour
● sortie du premier SDK le 12 Novembre 2007
antislashn.org Android - Présentation de la plateforme 1 - 4/15
Généralités● Le source du SDK est mis à disposition sous licence Apache
2.0● le 21 Octobre 2008● lien : http://source.android.com/
● Android Market est lancé en Novembre 2008● lien : https://market.android.com
● Octobre 2008 : sortie du premier samrtphone Android aux Etats-Unis
● Mars 2009 en France● 2009 : premières tablettes Android
● vrai succès à partir de début 2011, avec la version Android 3.0
antislashn.org Android - Présentation de la plateforme 1 - 5/15
Présentation de la plateforme● Principales caractéristique
● environnement de développement complet– émulateur de téléphone, outils de débogage, mesure des performances, …
● framework applicatif● machine virtuelle Dalvik
– optimisée pour les appareils nomades
● navigateur intégré– WebKit
● graphisme 2D et 3D● base de données SQLite● CODEC audio et vidéo (MPEG4, MP3, AAC, PNG, …)● options matérielles : téléphonie GSM, caméra, GPS, accéléromètre,
boussole, EDGE, Wifi, Bluetooth, …
antislashn.org Android - Présentation de la plateforme 1 - 7/15
Application Android
● Langage de développement : Java● attention, toutes les classes du JDK ne sont pas disponibles
– Swing par exemple
● possibilité d'utiliser du C pour certaines parties critiques– utilisation du NDK (Native Development Kit)
● Les outils du SDK compilent le code Java et les ressources associées
● création d'un fichier .apk qui contient toute l'application et ses ressources
– c'est ce fichier qui sera installé sur la plateforme Android
● Toutes les applications Android ont les même droits● même pied d'égalité que les applications natives
antislashn.org Android - Présentation de la plateforme 1 - 8/15
Application Android
● Une fois installée, une application Android est exécutée au sein d'un sandbox
● Le système d'exploitation Android est basé sur Linux● une application Android est un utilisateur du système d'exploitation● chaque application reçoit par défaut un identifiant unique
– user ID, seulement connu par Linux, pas par l'application
– l'OS positionne les permissions sur les fichiers de l'application afin que seule celle-ci puisse les utiliser
● une application est exécutée dans sa propre VM (Virtual Machine)● par défaut une application est exécutée dans un process Linux
– le process est démarré par Android si un composant de l'application doit être exécuté
– le process est tué lorsque l'application se termine ou si d'autres applications ont besoin de mémoire
antislashn.org Android - Présentation de la plateforme 1 - 9/15
Application Android● Il existe 4 types de composant applicatif
● dont les objectifs et cycles de vie sont différents● activité (activity) : interface graphique pour l'utilisateur
– classe Activity
● service (service) : composant exécuté en tâche de fond, sans interface graphique
– exemple : écoute de musique
– classe Service
● fournisseur de données (content provider) : gère et partage des données applicatives
– exemple : les contacts
– classe ContentProvider
● récepteur broadcast (broadcast receiver) : réagit à des messages, systèmes ou applicatifs
– mise hors tension, baterie faible, …
– classe BrodcastReceiver
antislashn.org Android - Présentation de la plateforme 1 - 10/15
Application Android● Une application Android n'a accès qu'à ses propres ressources
● politique "principe of least privilege"● environnement sécurisé qui interdit à l'application d'utiliser le
système sans en avoir la permission● Il est possible de donner le même user ID à plusieurs
applications● les applications sont exécutées dans le même process Linux● les application partage la même VM● permet de partager des ressources
● Une application doit posséder les permissions adéquats pour accéder aux composants du système
● liste des contacts, APN (Appareil Photo Numérique), SMS, ...
antislashn.org Android - Présentation de la plateforme 1 - 11/15
Versions Android et SDK
● Le système Android évolue très vite● ce qui est une marque de dynamisme● ce qui provoque une fragmentation importante des plateformes● nécessite un développement basé sur une version minimale
répandue● Pour les développeurs, Google met à disposition un SDK
(Software Development Kit)● lien : http://developer.android.com/sdk/index.html
● En plus du SDK il existe des bibliothèques tiers● leur support n'est pas obligatoire par les intégrateurs● exemples : API Google, Samsung, LG, ...
antislashn.org Android - Présentation de la plateforme 1 - 12/15
Versions Android et SDK● La version 1.0 est sortie en septembre 2008
● c'est la version 1.1 qui fut commercialisée en France– sortie en Février 2009
● Passage direct à la version 1.5● prise en charge de la détection de rotation, de
l'accéléromètre, enregistrement vidéo, App Widgets● La version 1.6 apporte le support de plusieurs résolutions● Les versions 2 se sont succédées rapidement
● HTML5, Wifi, stockage externe, NFC, VoIP, SIP, …● Étape importante : la version 3, conçue spécifiquement
pour les tablettes
antislashn.org Android - Présentation de la plateforme 1 - 13/15
Versions Android et SDK
● Il coexistait deux branches de versions● version 3 pour les tablettes
– version 3.2 actuellement● version 2 pour les smart phones
– version 2.3.4 actuellement
● Depuis la version 4● fusion entre téléphones, tablettes et télévisions
antislashn.org Android - Présentation de la plateforme 1 - 14/15
Historique des versionsPlateforme Nom API Level Date
Android 1.1 2
Android 1.5 Cupcake 3 Avril 2009
Android 1.6 Donet 4 Septembre 2009
Android 2.1 Eclair 7 Janvier 2010
Android 2.2 Froyo 8 Mai 2010
Android 2.3 Gingerbread 9 Décembre 2010
Android 3.0 Honeycomb 11 Janvier 2011
Android 4.0 Ice Cream Sandwich 14 Octobre 2011
Android 4.1 Jelly Bean 16 Juillet 2012
Android 4.4 KitKat 19 Octobre 2013
Android 5.0 L ????? 20 courant 2014
antislashn.org Android - Présentation de la plateforme 1 - 15/15
Quelle cible choisir ?
● Google publie la répartition d'utilisation des versions● informations collectées via Google Play
– lien : http://developer.android.com/about/dashboards/index.html
● ici en date du 21/03/2014
antislashn.org Android - Outils de développement 2 - 2/48
Outils du développeur
● Présentation des outils● Eclipse avec ADT
– ADT : Android Development Tools● le SDK● le SDK et AVD Manager
– AVD : Android Virtual Device● le ADB : Android Debug Bridge● le DDMS : Dalvik Debug Monitor Server
● Android Studio : autre outil mis à disposition par Google, basé sur IntelliJ IDEA● http://developer.android.com/sdk/index.html
antislashn.org Android - Outils de développement 2 - 3/48
Installation du plugin ADT
● Prérequis● JDK 1.6 installé● Eclipse installé
– la version pour le développement Java de base suffit
● Installer le SDK● télécharger l'archive de démarrage
– contient les outils de base, pas les APIS– http://developer.android.com/sdk/index.html
● décompresser l'archive dans un répertoire– nous y ferons référence sous l'appellation SDK_HOME
antislashn.org Android - Outils de développement 2 - 4/48
Installation du plugin ADT
● Démarrer Eclipse● Sélectionner l'installation de nouveaux plugins
● Help → Install New Software
antislashn.org Android - Outils de développement 2 - 5/48
Installation du plugin ADT
● Cliquer sur le bouton Add de l'assistant d'installation
● Ajouter le repository● remplir les deux champs
– Name : ADT Plugin– Location : https://dl-ssl.google.com/android/eclipse/– puis OK
antislashn.org Android - Outils de développement 2 - 6/48
Installation du plugin ADT
● Une fois que les outils sont affichés● sélectionner Select All
– attention : il faut que CDT soit installé pour que le NDK puisse être installé
● cf annexe A
● puis Next
antislashn.org Android - Outils de développement 2 - 7/48
Installation du plugin ADT
● Cliquer sur Next dans la fenêtre suivante● Accepter les licences
● puis cliquer sur Finish
antislashn.org Android - Outils de développement 2 - 8/48
Installation du plugin ADT
● Accepter l'alerte de sécurité
● Puis redémarrer Eclipse
antislashn.org Android - Outils de développement 2 - 9/48
Installation du plugin ADT
● Au redémarrage la version du plugin est vérifié● accepter l'éventuelle mise à niveau● ou sélectionner le répertoire d'installation du plugin● puis Finish
antislashn.org Android - Outils de développement 2 - 10/48
Installation du plugin ADT
● Les plate-formes cibles ne sont pas installées● une fenêtre peut le signaler
● Installation des API● dans la barre d'outils sélectionner le "SDK Manager"
● Dans la fenêtre suivante, sélectionner les niveaux d'API souhaités
antislashn.org Android - Outils de développement 2 - 11/48
Installation du plugin ADT
● Cliquer sur le bouton Install xx packages● Accepter toutes les licences puis cliquer sur Install
antislashn.org Android - Outils de développement 2 - 12/48
Installation du plugin ADT
● le téléchargement des plate-formes démarre● cette étape peut être assez longue
antislashn.org Android - Outils de développement 2 - 13/48
Le SDK
● Une fois l'installation terminée le répertoire d'installation du SDK comporte l'ensemble des outils, documentations, exemples, plateformes cibles
● L'installation étant relativement lente, ce répertoire peut être copier sur les autres machines
antislashn.org Android - Outils de développement 2 - 14/48
Émulateur AVD
● AVD : Android Virtual Device● émulateur de matériel● complètement configurable
● Avant d'utiliser un émulateur il faut le créer
antislashn.org Android - Outils de développement 2 - 15/48
Émulateur AVD
● L'émulateur Android peut être lancé● via Eclipse● via la ligne de commande
antislashn.org Android - Outils de développement 2 - 16/48
Émulateur AVD
● L'émulateur se comporte (presque) comme un téléphone● possibilité de changer les réglages de base
– langue, format date et heure, …● d'ajouter des contacts● de supprimer des applications● de recevoir des SMS et des appels téléphoniques
– depuis l'onglet "Emulator Control"– depuis un autre émulateur
● en précisant le numéro d'écoute de l'émulateur au lieu d'un numéro de téléphone
antislashn.org Android - Outils de développement 2 - 17/48
Émulateur AVD
● Ligne de commande● dans le répertoire tools● emulator -avd <avd_name> [-<option> [<value>]] …
– exemple : emulator -avd Samsung_S
● documentation des options de la ligne de commande– http://developer.android.com/tools/help/emulator.html
● Utilisation de l'émulateur derrière un proxy● en ligne de commande ajouter l'option
– -http-proxy <proxy>
● le proxy peut-être réglé dans l'émulateur lui-même
antislashn.org Android - Outils de développement 2 - 18/48
Émulateur AVD
● Réglage du proxy dans l'émulateur● Applications … Paramètres … Sans fils et réseaux
– Réseaux mobiles ... Nom des points d'accès … TelKila
antislashn.org Android - Outils de développement 2 - 19/48
Émulateur AVD
● L'émulateur peut être contrôlé● par le clavier du PC pour certaines opérations
– Ctrl-F11 et Ctrl-F12 pour le mode portrait / paysage par exemple
– l'ensemble des raccourcis est disponible à ● http://developer.android.com/tools/help/emulator.html
● par la vue "Emulator Control" dans Eclipse
antislashn.org Android - Outils de développement 2 - 20/48
Outil adb
● adb : Android Debug Bridge● Permet de se connecter sur l'émulateur
● ou sur un téléphone réel connecté en mode debug● Programme articulé autour de 3 composants
● un client exécuté sur la machine de développement– lancé par la console ou le plugin ADT
● un serveur qui s'exécute en arrière plan sur la machine de développement
● un démon exécuté sur chaque émulateur
antislashn.org Android - Outils de développement 2 - 21/48
Outil adb
● Le serveur maintient un client adb liée à un démon adb● émulateur 1 en 5554, client adb 1 en 5555● émulateur 2 en 5556, client adb 1 en 5557
● adb permet ● de connaître la liste des émulateur● d'installer des applications
● adb emulator-5556 install hello.apk
● de copier des fichiers vers/depuis l'émulateur● d'exécuter des commandes shell sur l'émulateur
– se connecter à la base de données SQL par exemple
antislashn.org Android - Outils de développement 2 - 22/48
Outil adb
● Quelques commandes adb● adb start-server
– démarre le serveur adb s'il ne l'est pas– eclipse peut être configuré pour utiliser un serveur externe
● adb kill-server– arrête le serveur
● adb devices– liste les matériels et émulateurs attachés
antislashn.org Android - Outils de développement 2 - 23/48
Outil adb
● Quelques commandes adb● adb [-d | -e | -s <serialNumber>] command
– envoie d'une commande adb● -d : vers le seul matériel connecté● -e : vers le seul émulateur connecté● -s <serialNumber> : vers un matériel ou émulateur connecté● command : une commande adb● si un seul matériel ou émulateur est connecté -d, -e ou -s peut être
omis
● adb -e shell– passage en mode shell
● ici sur le seul émulateur connecté
antislashn.org Android - Outils de développement 2 - 24/48
DDMS
● Dalvik Debug Monitor Server● outil de debug
● Intégré à Eclipse● perspective DDMS
● Ligne de commande● tools/ddms
antislashn.org Android - Outils de développement 2 - 25/48
DDMS
● DDMS permet● de suivre l'utilisation du tas● de suivre les allocations d'objets et mémoire● de travailler sur le système de fichier de l'émulateur● de voir les threads executés sur l'émulateur● d'effectuer du profiling de méthode
– nombre d'appels, temps d'exécution, …● Debug.startMethodTracing() et Debug.stopMethodTracing()
– à partir d'Android 2.1● 2.1 : doit avoir une carte SD et la permission d'écriture sur la carte SD● à partir de 2.2 : plus de SD nécessaire, les traces de logs sont
envoyés vers l'environnement de développement
antislashn.org Android - Outils de développement 2 - 26/48
DDMS
● Vue File Explorer
mouvements de fichiers entrel'équipement et le PC
suppression et ajout dansle système de fichier de l'équipement
antislashn.org Android - Outils de développement 2 - 27/48
DDMS
● Vue des threads actifs● il faut d'abord lancer la capture
thread de l'application
thread du garbage collector
thread dédié à la réception des signaux Linux
threads systèmes
● ID : identifiant du thread dans la VM● Tid : identifiant du thread Linux● Status
● running, sleeping, monitor, wait, native, vmwaait, zombie, init, starting● * si deamon
● utime : durée cumulée de l'exécution du code utilisateur (en "jiffies", 10ms)● stime : durée cumulée de l'exécution du code système (en "jiffies", 10ms)● Name : nom du thread
antislashn.org Android - Outils de développement 2 - 28/48
DDMS
● Vue Emulator Control● envoi de SMS● émulation d'appel
téléphonique● envoi de points de
géolocalisation
antislashn.org Android - Outils de développement 2 - 29/48
DDMS
● DDMS permet aussi d'interagir avec l'émulateur● envoi de SMS● émulation d'appel téléphonique vers un émulateur● mise à jour de la géolocalisation du téléphone
– manuellement ou par fichier● GPX : GPS eXchange file● KML : Keyhole Markup Language
antislashn.org Android - Outils de développement 2 - 30/48
Débogage
● Le débogage sous Eclipse est effectué de manière classique● par utilisation de traces dans les sources
– classe Log● par mise en place de points d'arrêts
– lancer alors l'application en mode debug
antislashn.org Android - Outils de développement 2 - 31/48
Gestion des logs
● L’outil logcat permet de visualiser les logs du système de logs Android● logcat est utilisable via adb ou DDMS
● Par défaut les logs sont dirigés vers /dev/log/main● deux autres journaux de logs existent
– /dev/log/radio pour les activité réseau et téléphone– /dev/log/events pour les événements système
● Les sorties vers les flux out et err sont redirigés vers /dev/null● utilisation de System.out ou System.err
antislashn.org Android - Outils de développement 2 - 32/48
Gestion des logs
source : elinux.org/Android_Logging_System
antislashn.org Android - Outils de développement 2 - 33/48
Gestion des logs
● Classe Log● ne comporte que des méthodes statiques● signatures des méthodes raccourci
● d(...) pour DEBUG, e(...) pour ERROR
– static int method(String tag, String msg)– static int method(String tag, String msg,
Throwable tr)● tag : identificateur du message● msg : message● tr : exception
● méthode générique– static int println(int priority, String tag,
String msg)● priority : DEBUG, ERROR, etc.
antislashn.org Android - Outils de développement 2 - 34/48
Gestion des logs
● Niveaux de log● VERBOSE – méthode Log.v(...)● DEBUG – méthode Log.d(...)● INFO – méthode Log.i(...)● WARN – méthode Log.w(...)● ERROR – méthode Log.e(...)● ASSERT● méthode Log.wtf(...)
– "What a Terrible Failure" : erreur ne devant jamais arriver
antislashn.org Android - Outils de développement 2 - 35/48
Gestion des logs
● Tag d'identification● souvent le nom de la classe● bonne pratique : déclarer une constante dans la classeprivate static final String tag = SensorListActivity.class.getCanonicalName();
antislashn.org Android - Outils de développement 2 - 36/48
Documentation de référence
● Disponible en ou hors connexion● sur internet :http://developer.android.com/reference/packages.html
● dans le répertoire doc du SDK
antislashn.org Android - Outils de développement 2 - 37/48
Documentation de référence
● Possibilité de tri par classe
● Champ de recherche
antislashn.org Android - Outils de développement 2 - 38/48
Documentation de référence
● Niveau d'API à partir de laquelle la classe peut-être utilisée
antislashn.org Android - Outils de développement 2 - 39/48
Développer sur un équipement réel
● La plupart des équipement tournant sous Android peuvent être utilisés pour tester et déboguer une application● certains fabricants bride le support sur leur matériel
– Archos, autres ???– voir sur le site du fabricant pour la procédure à suivre
● http://www.archos.com/support/support_tech/updates_adb.html?country=fr&lang=fr
● Configuration du développement sur le matériel● l'application doit être déclarée comme "débogable"
– dans l'élément <application>, ajouter l'attribut android:debuggable="true"
● le téléphone doit être configuré en mode USB Debugging
antislashn.org Android - Outils de développement 2 - 40/48
Développer sur un équipement réel
● L'activation du mode développeur dépend du niveau d'API● < Android 4
– l'activation du mode développeur se trouve dans la gestion des applications
● < Android 4.2– entrée "Options pour les développeurs" dans les paramètres
● > Android 4.2– le menu "Options pour les développeurs" doit être activée
● taper 7 fois sur l'item "Numéro de build" du menu "A propos du téléphone"
● le mode développeur est alors activé, et l'entrée "Options pour les développeurs" est affichée
antislashn.org Android - Outils de développement 2 - 41/48
Développer sur un équipement réel
● Passage en mode USB debugging sur Android 1.x et 2.x● Settings → Applications → Development
antislashn.org Android - Outils de développement 2 - 42/48
Développer sur un équipement réel
● Passage en mode USB debugging sur Android 1.x et 2.x● puis activer le débogage USB
antislashn.org Android - Outils de développement 2 - 43/48
Développer sur un équipement réel
● Passage en mode USB debugging sur Android 3.0● Settings → Applications → Development
antislashn.org Android - Outils de développement 2 - 44/48
Développer sur un équipement réel
● Passage en mode USB debugging sur Android 3.x● puis activer le debogage USB
antislashn.org Android - Outils de développement 2 - 45/48
Développer sur un équipement réel
● Passage en mode USB debugging sur Android 4.x● Settings → Developer options● attention depuis Android 4.2 l'entrée est cachée
– l'activation est effectuée en tapant 7 fois sur le numéro de build du téléphone
antislashn.org Android - Outils de développement 2 - 46/48
Développer sur un équipement réel
● Passage en mode USB debugging sur Android 4.x● puis activer le débogage USB
● De très nombreux outils sont disponibles pour aider le développeur
antislashn.org Android - Outils de développement 2 - 47/48
Développer sur un équipement réel● Paramétrer le poste de développement
● Windows– installer le driver USB du matériel– ce driver est fourni par le constructeur– cf : http://developer.android.com/tools/extras/oem-usb.html
● Mac, CentOS– rien à faire
● Ubuntu– ajouter une règle au fichier /etc/udev/rules.d/51-android.rules
● SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev"
● où {idevendor} correspond à un identifiant– http://developer.android.com/tools/device.html
● exécuter– chmod a+r /etc/udev/rules.d/51-android.rules
antislashn.org Android - Outils de développement 2 - 48/48
Développer sur un équipement réel
● Déboguer via le Wifi● les appareils ne possédant qu'un seul port USB il est
parfois nécessaire de déboguer via le réseau WIFI● étapes à suivre
– activer le WIFI● récupérer l'adresse TCP IP du matériel dans les propriétés WIFI
– connecter le matériel en USB– vérifier que le débogage fonctionne bien mode USB– lancer la commande : adb tcpip 5555– puis lancer : adb connect <ip_matériel>:5555– pour revenir au mode usb : adb usb
antislashn.org Android - Hello, world 3 - 2/20
"Hello, world"
● création du projet● liaison avec l'architecture de l'application
● Activity● fichier de AndroidManifest.xml
● utilisation d'un émulateur
antislashn.org Android - Hello, world 3 - 3/20
"Hello, world"
● Création du projet● File...New...Project● la fenêtre de choix de projet s'affiche
– choisir un nouveau projet Android
antislashn.org Android - Hello, world 3 - 4/20
"Hello, world"
● L'assistant de création de projet s'affiche● donner un nom au projet, puis Next
antislashn.org Android - Hello, world 3 - 5/20
"Hello, world"
● Dans l'écran suivant choisir le SDK cible● ici le SDK version 1.6, puis Next
antislashn.org Android - Hello, world 3 - 6/20
"Hello, world"
● Donner un nom à l'application, et choisir un package
antislashn.org Android - Hello, world 3 - 7/20
"Hello, world"
sources de notre application
activité (écran) de l'application
répertoire où sont déposés lesressources générées
fichier R.java généré par les outils Android
bibliothèques du SDK cible
répertoire des ressources
fichier de configuration de l'application
répertoire des données brutes : MP3, ...
propriétés du projet
antislashn.org Android - Hello, world 3 - 8/20
"Hello, world"● Certains fichiers sont maintenus par le plugin ADT
● il ne faut pas les éditer, ils sont mis à jour automatiquement– R.java– default.properties
● Les ressources contenues dans le répertoire res peuvent être modifiées lors la compilation● pour optimisation● se retrouvent dans les ressources R.java
● Les ressources du répertoire assets ne sont pas impactées par la compilation● possibilité de les lire en tant que flux d'octets
antislashn.org Android - Hello, world 3 - 9/20
"Hello, world"
● Pour exécuter l'application sélectionner le projet● puis avec un click droit, sélectionner
– Run As … Android Application
● Si un émulateur est configuré il est automatiquement chargé● l'application est lancée● si aucun émulateur n'est configuré l'écran de gestion
des émulateurs est affichée● si plusieurs émulateurs sont configurés, en choisir un
● Une fois l'émulateur chargé il est préférable de ne pas le fermer
antislashn.org Android - Hello, world 3 - 10/20
Ressources de l'application● Les ressources sont des données utilisables par l'application
● elles sont intégrées au binaire de l'application● res/anim : animations de transition au format XML● res/color : couleurs définis dans des fichiers XML● res/drawable : images, plusieurs densités d'écran sont disponibles
(hdpi, mdpi et ldpi)● des ressources images peuvent être spécifiées pour une configuration
matérielle et/ou logicielle précise, le nom du dossier de ressource est alors complété par des qualificatifs séparés par des traits d'union
– largeur d'écran, orientation de l'écran, langue système, ...
● res/layout : interfaces graphiques● res/values : valeurs utilisées par l'application
● les valeurs sont définies dans un fichier XML
antislashn.org Android - Hello, world 3 - 11/20
Ressources de l'application● Chaque ressource du dossier res possède un identifiant entier
unique● permet d'atteindre depuis le code Java, ou XML, une ressource
– cette valeur peut changer au grès des ajouts et suppression de ressources
● pour éviter le codage en dur de ces valeur, des constantes sont créées dans une classe R.java
public final class R { public static final class attr { } public static final class drawable { public static final int ic_launcher=0x7f020000; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; }}
antislashn.org Android - Hello, world 3 - 12/20
Ressources de l'application● Le nom complet de la constante est composé :
● du nom du package– facultatif car il s'agit du package courant
● du type de ressource– correspond au sous dossier res
● du nom de la ressource– pour les ressources situées dans res/values, le nom est celui défini dans
le fichier xml
<?xml version="1.0" encoding="utf-8"?><resources> <string name="hello">Hello World, HelloActivity!</string> <string name="app_name">Hello</string></resources>
antislashn.org Android - Hello, world 3 - 13/20
Ressources de l'application
● syntaxe Java pour accéder à une ressource : [package.]R.type.nomR.string.app_name
● syntaxe XML pour accéder à une ressource :
@[package:]type/nom@string/app_name
antislashn.org Android - Hello, world 3 - 14/20
Structure de l'application "Hello, world"● Le fichier AndroidManifest.xml
● contient la configuration principale de l'application– composants applicatifs, point d'entrée principal, sécurité et droits,
etc.
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.antislashn.android.hello" android:versionCode="1" android:versionName="1.0" >
<uses-sdk android:minSdkVersion="4" />
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".HelloActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
</manifest>
antislashn.org Android - Hello, world 3 - 15/20
"Hello, world" - AndroidManifest.xml
● Les balises et attributs de ce fichier XML sont très nombreux● beaucoup sont facultatifs
● Certains seront détaillées au cours de cette formation● au fur et à mesure de leur utilisation
● Balise racine : manifest● attributs
– package : package de l'application
– versionCode : version de l'application (numérique)
– versionName : version de l'application (string)
antislashn.org Android - Hello, world 3 - 16/20
"Hello, world" - AndroidManifest.xml
● Balise uses-sdk● indique les versions de SDK pour que l'application
puisse être exécutée● attributs
– minSdkVersion : niveau minimum pour que l'application puisse être utilisée
– targetSdkVersion : niveau de l'API utilisé lors du développement – utilisé par Android pour ajouter si nécessaire des mécanismes de compatibilité : thèmes graphiques, densité écran, ...
antislashn.org Android - Hello, world 3 - 17/20
"Hello, world" - AndroidManifest.xml
● Balise application● informations sur l'application● attributs
– icon : icône de l'application● valeur : @drawable/ic_launcher qui référencie la ressource ic_launcher.png située dans un des répertoire res/drawable, en fonction de la densité d'écran
– label : titre de l'application – il est préférable d'utiliser des références à des ressources plutôt qu'une chaine de caractères
● valeur : @strinf/app_name qui référencie la ressource de type string contenue dans le fichier res/values/string.xml
● application contient des balises enfants
antislashn.org Android - Hello, world 3 - 18/20
"Hello, world" - AndroidManifest.xml● Balises filles
● elles seront vues en détails lors des prochains chapitres● activity
– défini une activité (écran)
– l'activité est lancée par une intention (intent)
● service– défini un service
● provider– défini un fournisseur de données
● reicever– défini un récepteur de messages
● uses-library– librairies utilisées
antislashn.org Android - Hello, world 3 - 19/20
"Hello, world" - activity
● Le nom (attribut name) de l'activité (balise activity) référencie la classe HelloActivity● préfixée par le point, car appartenant au package
courant– la méthode onCreate(...) est le point d'entrée de
l'application● invoque la méthode onCreate() de la classe mère● charge l'écran de l'activité
public class HelloActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }}
antislashn.org Android - Hello, world 3 - 20/20
"Hello, world" - IHM
● L'écran de l'application est décrite dans un fichier XML● ici le fichier res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" />
</LinearLayout>
gestionnaire de positionnement
composant de type texte
ressource définie dans res/values/string.xml
antislashn.org Android - architecture et développement 4 - 1/17
Application Androidarchitecture et développement
antislashn.org Android - architecture et développement 4 - 2/17
Cycle de développement
● création du projet● codage● compilation
● effectuée en deux étape– java vers .class avec l'outil javac
– .class vers .dex avec l'outil dx
● création de l'archive apk● clé pour le développement
antislashn.org Android - architecture et développement 4 - 3/17
Architecture d'une application
● Une application Android est constituée d'un ou plusieurs modules applicatifs :● Activity : code de gestion d'une IHM● Service : traitement exécuté en tâche de fond● ContentProvider : exposition de données à d'autres
applications● BroadcastReceiver : récepteur de messages
● Les modules applicatifs communiquent entre eux par des messages● de type Intent
antislashn.org Android - architecture et développement 4 - 4/17
Architecture d'une application
● Le contexte applicatif est accessible par la classe Context● les types Activity et Services dérivent de Context● permet de lancer des intentions vers un autre
composant– qui appartient à l'application ou non
● permet de récupérer les ressources de l'application– répertoire, base de données, ...
antislashn.org Android - architecture et développement 4 - 5/17
Architecture d'une application
● La configuration de l'application est décrite dans le fichier AndroidManifest.xml● nom de l'application● icônes● compatibilité : SDK, écrans, présence d'un clavier, ...● déclaration des modules applicatifs● déclarations des filtres de messages● déclaration des permissions : utilisation GPS, internet,
etc.● classe d'instrumentation de l'application
antislashn.org Android - architecture et développement 4 - 6/17
Architecture d'une application
● Fichier AndroidManifest.xml<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.antislashn.android.hello" android:versionCode="1" android:versionName="1.0" >
<uses-sdk android:minSdkVersion="4" />
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".HelloActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
</manifest>
antislashn.org Android - architecture et développement 4 - 7/17
Les ressources
● Les ressources nécessaires à l'application sont intégrées dans le répertoire res du projet● ses ressources seront compilées avec
l'application● un identifiant unique est associé à chacune
des ressources– voir la classe générée R.java– un fichier ic_launcher.png placé dans un répertoire
(ou sous-répertoire) de res/drawable sera utilisable par :
● R.drawable.ic_launcher en java● @drawable/ic_launcher en XML
antislashn.org Android - architecture et développement 4 - 8/17
Les données brutes
● Les données brutes (audio, vidéo, …) sont placées dans le répertoire assets● la taille maximale autorisée est de 1 Mo
– pour les fichiers compressé par APK (csv, txt,...)– pas pour les fichiers binaires (mp3, png, ...)
● elles sont accessible via un AssetManager– une instance d'AssetManager peut être récupérée par le Context
● méthode getAssets()
– la méthode open(String fileName) renvoie un InputStream sur la ressource désirée
antislashn.org Android - architecture et développement 4 - 9/17
Le bus de message
● Les différents modules applicatifs ne sont pas directement instanciés par le développeur
● Un bus de messages permet au système de choisir le composant à monter en mémoire● les messages sont de type Intent● les intentions décrivent quelle est l'opération qui devra
être effectuée– plusieurs composants applicatifs peuvent répondre à un
même Intent● l'utilisateur aura alors le choix
antislashn.org Android - architecture et développement 4 - 10/17
Le bus de messages
● Un message est principalement constitué● d'une action
– affichage, composition d'un numéro de téléphone, démarrage d'un module, ...
● d'une catégorie– informations supplémentaires pour l'action à mener
● préférences utilisateur, affichage dans les applications, …
● d'autres données : type MIME, composant à invoquer, données supplémentaires, URI
antislashn.org Android - architecture et développement 4 - 11/17
Le bus de message
● Un composant décrit une configuration de messages auxquels il est susceptible de répondre● dans le fichier AndroidManifest.xml● balise <intent-filter>
– exemple : point d'entrée d'un application
<intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /></intent-filter>
antislashn.org Android - architecture et développement 4 - 12/17
Le bus de message
Producteur
Système AndroidModule applicatif
Intent
IntentResolver
Application 2
Activité
Activité
IntentFilter
IntentFilter
Application 1
Activité
Service
IntentFilter
IntentFilter
Le composant dont le filtred'intention correspond estactivé
antislashn.org Android - architecture et développement 4 - 13/17
Bonnes pratiques
● Le développement sous Android est différent d'un développement Java classique
● Il existe des bonnes pratiques liées à la plateforme Android● codage● ergonomie● compatibilité entres matériels● design
antislashn.org Android - architecture et développement 4 - 14/17
Bonnes pratiques de codage
● Ne pas perdre de vue que l'application est exécutée sur une plateforme dont les ressources sont limitées
● Minimiser la création d'objets● Ne pas utiliser les getteurs / setteurs au sein de la
classe● préférer la lecture ou l'affectation directe des propriétés
● Déclarer static les méthodes qui peuvent l'être● Préférer les constantes plutôt que les énumération
● enum est une classe
antislashn.org Android - architecture et développement 4 - 15/17
Bonnes pratiques d'ergonomie
● Souvent sans clavier et dispositif de pointage● le doigt est utilisé sur l'écran
● Ne pas dessiner des widgets trop petits● taille recommandée aux alentour de 9mm, soit 48dp
– dp : density-independant pixels– http://developer.android.com/design/style/metrics-grids.html
antislashn.org Android - architecture et développement 4 - 16/17
Bonnes pratiques d'ergonomie
● Utiliser le retour haptique et le changement de couleur des boutons● attribut android:hapticFeedbackEnable
●
antislashn.org Android - architecture et développement 4 - 17/17
Bonnes pratiques de design
● Les icônes de lancement d'applications font une taille de 48x48 dp● les icônes de Play Store font 512 x 512 px
● Utiliser les icônes prédéfinies pour la barre d'action● téléchargement :
https://dl-ssl.google.com/android/design/Android_Design_Icons_20120229.zip
antislashn.org Android - composants graphiques de base 5 - 2/56
Les écrans Android
● En général, une application Android possède une interface utilisateur (IHM, GUI)
● La configuration matérielle exacte sur laquelle sera exécutée l'application n'est pas connue● taille écran, densité, profondeur de couleur, …
● Caractéristiques d'un écran● taille : diagonale de 6,5 cm à 30 cm
– 1 pouce = 2,54 cm● résolution
– QVGA : 240 x 320 pixels– WXGA 16/9 : 1366 x 768 pixels– WXGA 16/10 : 1280 x 800 pixels
antislashn.org Android - composants graphiques de base 5 - 3/56
Les barres système
● La barre d'état résume l'état du matériel et affiche certaines notifications
● La barre de navigation permet de naviguer entre les applications / pages / accueil
source : Google
antislashn.org Android - composants graphiques de base 5 - 4/56
Les écrans Android
● Les écrans Android sont classés en :● petit (small) : diagonale de 2,5"● normal (normal) : diagonale de 4"● grand (large) : diagonale de 7"● très grand (xlarge) : diagonale de 10"
– depuis API 9
● La résolution est exprimée en points par pouce● dpi : dots per inch● mesure la densité de pixels sur l'écran
antislashn.org Android - composants graphiques de base 5 - 5/56
Les écrans Android
● La densité de pixels est classée en :● faible (ldpi) : 120 dpi● moyenne (mdpi) : 160 dpi● haute (hdpi) : 240 dpi● très haute (xhdpi) : 320 dpi
– depuis API 8
● Les caractéristiques d'un écran peuvent être récupérées via une instance de WindowManager
DisplayMetrics displayMetrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); Log.d("WindowManagerActivity", "Density DPI : "+displayMetrics.densityDpi);Log.d("WindowManagerActivity", "Resolution X : "+displayMetrics.widthPixels);Log.d("WindowManagerActivity", "Resolution Y : "+displayMetrics.heightPixels);
antislashn.org Android - composants graphiques de base 5 - 6/56
Les écrans Android
● Si les résolutions sont différentes pour une même taille d'écran les composants graphiques s'afficheront avec une taille différente● Google préconise l'utilisation de l'unité dp
– appelée aussi dip (density independent pixel)● ne pas confondre avec dpi
● il existe aussi une métrique pour les polices de caractères : sp (ou sip pour scale independent pixel)
● Il existe aussi :● px pour le pixel● in pour inch● mm pour millimètre
antislashn.org Android - composants graphiques de base 5 - 8/56
Les écrans Android
● Pour les images● Android recherche d'abord une ressource
correspondant à la densité utilisé par le matériel– dans res/drawable-hdpi, ldpi, mdpi
● sinon une ressource dans la densité la plus proche est utilisée et l'image est retaillée– ration 3 – 4 – 6 – 8 pour ldpi, mdpi, hdpi et xdpi– si une image existe en mdpi de 100x100 px
● un ratio 6/4 est utilisé pour un écran hdpi soit 150x150 px● un ratio ¾ est utilisé pour un écran ldpi soit 75x75 px
antislashn.org Android - composants graphiques de base 5 - 9/56
Les écrans Android
● Balise support-screens● depuis Android 1.6 (level 4)● balise fille de la balise manifest● permet d'indiquer les écrans supportés au système et
Android Market
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
antislashn.org Android - composants graphiques de base 5 - 10/56
Interface graphique● Les interfaces graphiques sont réalisées dans une activité
(activity) ou un fragment (fragment)● un écran peut alors être composé de plusieurs fragments● sera vu plus tard
● La réalisation de l'IHM peut être faite de manière● programmée : les composants graphiques sont créés par le
code Java et ajoutés à la vue– permet de générer une vue dynamiquement
● déclarée : dans des fichiers XML– séparation du code de la présentation
● les deux modes peuvent être utilisés– manipulation en java des composants déclarés en XML
antislashn.org Android - composants graphiques de base 5 - 11/56
Interface graphique
● Eclispe : plugin ADT● permet de créer la vue via un éditeur XML ou par
l'éditeur graphique (Graphical Layout)
antislashn.org Android - composants graphiques de base 5 - 12/56
Hiérarchie des composants graphiques
● les fragments● les vues● les gestionnaires de placement
● layout manager● arbre des composants graphiques
antislashn.org Android - composants graphiques de base 5 - 13/56
Hiérarchie des composants graphiques
● La vue est l'élément de base de l'IHM● classe View
– tous les composants graphiques héritent de cette classe– les classes ViewGroup contiennent plusieurs composants
graphiques● pattern Composite
antislashn.org Android - composants graphiques de base 5 - 14/56
Hiérarchie des composants graphiques● Principaux attributs XML des View
● background : fond de la vue (couleur, image)● clickable : indique si réaction aux clics● id : identifiant unique de la vue● minHeight et minWidth : hauteur et largeur minimales● onClick : méthode à invoquer lors d'un clic● padding : dimension de la marge interne pour les 4 côté de
la vue– cf paddingBottom, paddingLeft, paddingRight, paddingTop
● tag : associe un objet au composant● visibility : indique si le composant est visible ou non
antislashn.org Android - composants graphiques de base 5 - 15/56
Les layouts● Les layouts sont de type ViewGroup
● conteneurs de composants graphiques● gèrent le placement des composants● chaque layout offre une structure de positionnement qui lui
est propre● Attributs XML obligatoires
● layout_width et layout_heigth : largeur et hauteur– valeurs possibles
● fill_parent : remplit l'espace du conteneur parent, moins la marge● wrap_content : se dimensionne en fonction du contenu du composant● match_parent : est remplacé par fill_parent depuis la version 8 du SDK● une valeur en dip, px, mm, in, ...
antislashn.org Android - composants graphiques de base 5 - 16/56
Les layouts
● Divers propriétés sont disponibles sur les layouts pour paramétrer l'affichage● voir en fonction des layouts
● Il faut penser en terme● d'orientation● modèle de remplissage● poids● gravité● remplissage
antislashn.org Android - composants graphiques de base 5 - 17/56
Les layouts
● Orientation (android:orientation)● des layouts, comme LinearLayout, présentent les
widgets en ligne ou en colonne● l'orientation peut-être modifiée en cours d'exécution
avec setOrientation(...)● Poids (android:layout_weigth)
● comment deux widgets se partagent l'espace disponible ?
● layout_weigth indique la proportion par widget– si 1 pour deux widgets l'espace libre est divisé en 2– si 1 pour un widget, et 2 pour le second, le second utilisera
deux fois moins d'espaces que le premier
antislashn.org Android - composants graphiques de base 5 - 18/56
Les layouts
● Modèle de remplissage● les widgets ont une taille "naturelle" qui repose sur le
texte affiché– que faire de l'espace restant ?
● les widgets peuvent fournir une valeur pour layout_width et layout_height– la valeur peut être
● une dimension précise : 120 dp● wrap_content pour que le widget occupe sa place naturelle● fill_parent pour que le widget occupe toute la place disponible
antislashn.org Android - composants graphiques de base 5 - 19/56
CONTENEUR
Les widgets de base
● Positionnement des widgets
WIDGET
top
padding
layout_margin
left
width
height
antislashn.org Android - composants graphiques de base 5 - 20/56
Les layouts
● Gravité● layout_gravity gère le placement du widget dans le
layout– indique au conteneur et au widget comment l'alignement doit
être effectué
● gravity gère le placement du texte dans le widget● Remplissage
● les widgets sont par défaut serrés les uns contre les autres– padding gère les 4 zones
– paddingTop, paddingBottom, paddingLeft, paddingRight gèrent le remplissage zone par zone
antislashn.org Android - composants graphiques de base 5 - 21/56
Les layouts
● Positions relatives par rapport à un conteneur● layout_alignParentTop : haut du widget aligné avec
celui du conteneur● layout_alignParentBottom : bas du widget aligné avec
celui du conteneur● layout_alignParentLeft : bord gauche du widget
aligné avec celui du conteneur● layout_alignParentRigth : bord droit du widget aligné
avec celui du conteneur● layout_alignCenterHorizontal : widget centré
horizontalement● layout_alignCenterVertical : widget centré
verticalement
antislashn.org Android - composants graphiques de base 5 - 22/56
Les layouts● Position relative des widgets
● attribuer un identifiant à tous les widgets devant être désignés (par @+id/... )
● désigner un widget dans un autre avec son identifiant (avec @id/... )
● le contrôle du placement d'un widget par rapport à un autre est effectué par :
– android:layout_above le widget doit être placé au-dessus de celui qu'il désigne
– android:layout_below le widget doit être placé sous celui qu'il désigne
– android:layout_toLeftOf le widget doit être placé à gauche de celui qu'il désigne
– android:layout_toRightOf le widget doit être placé à droite de celui qu'il désigne
antislashn.org Android - composants graphiques de base 5 - 23/56
Les layouts
● Alignement d'un widget par rapport à un autre● android:layout_alignTop le haut du widget est
aligné avec le haut du widget désigné● android:layout_alignBottom le bas du widget est
aligné avec le bas du widget désigné● android:layout_alignLeft le bord gauche du
widget est aligné avec le bord gauche du widget désigné
● android:layout_alignRight le bord droit du widget est aligné avec le bord droit du widget désigné
● android:layout_alignLBaseLine les lignes de base des deux widgets doivent être alignées
antislashn.org Android - composants graphiques de base 5 - 24/56
Les layouts
● Le plugin ADT simplifie la mise en place des layouts● affiche le résultat
antislashn.org Android - composants graphiques de base 5 - 25/56
FrameLayout
● Le plus simple des conteneurs● tous les éléments sont placés les uns au-dessus des
autres à partir du coin haut-gauche● le dernier élément graphique ajouté vient recouvrir les
autres éléments
antislashn.org Android - composants graphiques de base 5 - 26/56
LinearLayout
● Les composants sont placés les un après les autres, selon l'attribut d'orientation● verticalement : les uns sous les autres● horizontalement : les un après les autres, à la droite du
précédent
antislashn.org Android - composants graphiques de base 5 - 27/56
LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1">
...
</LinearLayout> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1">
...
</LinearLayout>
</LinearLayout>
antislashn.org Android - composants graphiques de base 5 - 28/56
LinearLayout
● Attributs utilisés dans l'exemple● orientation : orientation verticale ou horizontale● layout_width : largeur● layout_heigth : hauteur● layout_weight : proportion de la place prise par le
widget dans son parent ● gravity : poisition dans son conteneur● background : couleur du fond ● text : texte affiché● textSize : taille du texte
antislashn.org Android - composants graphiques de base 5 - 29/56
RelativeLayout
● Les positions des composants enfants sont précisées par rapport à la vue parente ou par rapport aux autres composants
antislashn.org Android - composants graphiques de base 5 - 30/56
RelativeLayout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/label" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Type here:"/> <EditText android:id="@+id/entry" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@android:drawable/editbox_background" android:layout_below="@id/label"/> <Button android:id="@+id/ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/entry" android:layout_alignParentRight="true" android:layout_marginLeft="10dip" android:text="OK" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@id/ok" android:layout_alignTop="@id/ok" android:text="Cancel" /></RelativeLayout>
antislashn.org Android - composants graphiques de base 5 - 31/56
RelativeLayout
● Attributs utilisés dans l'exemple● id : identifiant unique● layout_below : positionne le haut d'un widget en
dessous du widget référencé ● layout_alignParentRight : aligne le côté droit du
widget avec le côté droit de son parent● layout_marginLeft : espace pour la marge gauche● layout_toBeLeftOf : positionne le côté droit du
widget à gauche du widget référencer● layout_alignTop : aligne le haut du widget avec le
haut du widget référencé
antislashn.org Android - composants graphiques de base 5 - 32/56
TableLayout
● Les composants enfants sont disposés sous forme de tableau● les vues enfants sont des lignes de type TableRow● les composants graphiques sont insérés dans les lignes
antislashn.org Android - composants graphiques de base 5 - 33/56
TableLayout<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:stretchColumns="1">
<TableRow> <TextView android:layout_column="1" android:text="Open..." android:padding="3dip" /> <TextView android:text="Ctrl-O" android:gravity="right" android:padding="3dip" /> </TableRow>
<TableRow> <TextView android:layout_column="1" android:text="Save..." android:padding="3dip" /> <TextView android:text="Ctrl-S" android:gravity="right" android:padding="3dip" /> </TableRow>
<TableRow> <TextView android:layout_column="1" android:text="Save As..." android:padding="3dip" /> <TextView android:text="Ctrl-Shift-S" android:gravity="right" android:padding="3dip" /> </TableRow>
</TableLayout>
antislashn.org Android - composants graphiques de base 5 - 34/56
TableLayout
● Attributs utilisés dans l'exemple● layout_column : index de la colonne où doit être
positionné le widget● gravity : position du widget dans son conteneur● padding : espacement entre la bordure du widget et
son contenu
antislashn.org Android - composants graphiques de base 5 - 35/56
Autres layout
● Il existent d'autres gestionnaires de positionnement● seront vu plus tard● GridView : positionne les éléments dans une grille
– la grille est muni d'ascenseurs– les éléments sont ajoutés via un ListAdapter
● Mise en place d'onglets– nécessite une construction spécifique de layouts
● Liste déroulante– utilise une classe ListView
antislashn.org Android - composants graphiques de base 5 - 36/56
Autres layout
● Il existent d'autres gestionnaires de positionnement● seront vu plus tard● GridView : positionne les éléments dans une grille
– la grille est muni d'ascenseurs– les éléments sont ajoutés via un ListAdapter
● Mise en place d'onglets– nécessite une construction spécifique de layouts
● Liste déroulante– utilise une classe ListView
antislashn.org Android - composants graphiques de base 5 - 37/56
Mode déclaratif
● Mode le plus simple pour déclarer et réutiliser les IHM● les exemples précédents illustrent le mode déclaratif
● Création du fichier XML dans le répertoire res/layout● possibilité de fournir des layouts adaptés aux écrans
physiques dans les répertoires res/layout-small, res/layout-normal, res/layout-large, res/layout-xlarge
● des layouts adaptés à l'orientation de l'écran sont aussi possibles– ajouter le qualificatif port pour portrait et land pour paysage
● res/layout-port, res/layout-normal-land, ...
antislashn.org Android - composants graphiques de base 5 - 38/56
Mode déclaratif
● Utilisation du layout● une activité crée l'interface utilisateur● utilisation de la méthode setContentView(...) de
la classe Activity– prend en paramètre un identifiant correspondant à l'identifiant
du composant graphique● utilisation de la classe R.java
public class FrameLayoutActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }}
antislashn.org Android - composants graphiques de base 5 - 39/56
Programmation des IHM
● Mode plus puissants, mais plus complexe● ne facilite pas la réutilisation des IHM● n'utilise pas les stratégies de choix de ressource en
fonction du type d'écran– pas d'utilisation des fichiers XML res/layout-xxx
● Création du layout● instanciation
– le constructeur prend en argument le contexte de l'application
– Activity hérite de la classe Context● paramétrage du layout créé
– utilise une instance de ViewGroup.LayoutParams
antislashn.org Android - composants graphiques de base 5 - 40/56
Programmation des IHM
● Appel de la méthode setContentView(...)
public class LayoutProgrammationActivity extends Activity {/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);LinearLayout layout = new LinearLayout(this);LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);layout.setLayoutParams(params);this.setTitle("Exemple instanciation layout");setContentView(layout);
}}
antislashn.org Android - composants graphiques de base 5 - 41/56
Programmation des IHM
● Les modes déclaratif et programmatique sont souvent utilisés conjointement● l'IHM est décrite dans le fichier XML● le code java agit dynamiquement sur l'IHM● c'est ce mode de développement qui est privilégié
● Interactions entre le mode déclaratif et programmatique● le fichier XML déclare les composants graphique● le code java retrouve le widget qu'il doit manipuler
antislashn.org Android - composants graphiques de base 5 - 42/56
Programmation des IHM
● Récupération des widgets● le code java doit récupérer les widgets qui sont déclarés
dans le fichier XML● un identifiant est associé au widget, par l'attribut id
– id="@[+][package]id/nom_ressource"● le signe + signifie que l'identifiant doit être ajouté, il apparaîtra dans le
fichier R.java
● la méthode findViewById(...) permet de récupérer un widget– public View findViewById(int id)– l'identifiant est retrouvé par la classe R.java
antislashn.org Android - composants graphiques de base 5 - 43/56
Programmation des IHM
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/text_message" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /></LinearLayout>
public class ModeMixteActivity extends Activity {/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.main);TextView text = (TextView) findViewById(R.id.text_message);text.setText("Comment ça va ?");
}}
ajout de l'identifiant
récupération du widget
antislashn.org Android - composants graphiques de base 5 - 44/56
Les widgets de base● Nous allons présenter quelques widgets de base
● le nombre de composants Android évolue en fonction des versions
● le nombre de propriétés de chaque composant est impressionnant– les propriétés communes à tous les composants, plus les propriétés
spécifiques● atteint plusieurs dizaines de propriétés par composants
– ce référer à la documentation fournie avec le SDK pour plus de détails
● tous les composants font partie du package android.widget● D'autres composants seront présentés au fur et à mesure
des exemples et exercices
antislashn.org Android - composants graphiques de base 5 - 45/56
Les widgets de base
● Le tiroir "Form Widget" du plugin ADT permet de choisir les widgets disponibles en fonction du niveau de SDK choisi● attention, sur certaines plateformes
de développement, le rendu ne correspond pas à l'affichage réel– l'émulateur permet alors de vérifier les
attributs positionnés
antislashn.org Android - composants graphiques de base 5 - 46/56
View
● La classe View la classe de base utilisée par tous les widgets● View est spécialisée en ViewGroup pour les
conteneurs● Une vue occupe un rectangle dans l'interface
graphique● La vue est responsable de son affichage et de la
gestion des événement
antislashn.org Android - composants graphiques de base 5 - 47/56
View
● De nombreux événements sont exploitables● clic, survol, création, drag and drop, …● cf. la documentation
● Un ou plusieurs objets peuvent être attachés à une vue● notion de tag● voir les méthodes setTag(...) et getTag(...)
antislashn.org Android - composants graphiques de base 5 - 48/56
Les widgets de base
● La documentation permet de connaître, widget par widget, les attributs XML et les méthodes équivalentes Java● onglet "Reference"
antislashn.org Android - composants graphiques de base 5 - 49/56
TextView● Affichage d'un texte● Principales propriétés
● autoLink : convertit les liens HTTP et adresses mails en liens cliquables
● ellipsize : règle d'affichage du texte si plus long que la zone de visualisation
● height, width, maxHeight, maxWidth : hauteur et largeur● lines, minLines, maxLines : nombre de lignes● text : texte à afficher● textColor, textSize, textStyle : caractéristiques du texte● gravity : endroit où est afficher le texte dans le conteneur si la zone
d'affichage du texte est plus petit que le conteneur● drawableTop, drawableBottom, drawableLeft, drawableRight
: permet la gestion de l'affichage d'une ressource drawable à côté du texte
antislashn.org Android - composants graphiques de base 5 - 50/56
TextView
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="#FFF" android:textColor="#000" android:textSize="25sp" android:textStyle="italic" android:text="@string/hello" /></LinearLayout>
antislashn.org Android - composants graphiques de base 5 - 51/56
EditText
● Permet la saisie d'un texte● Hérite de TextView
● même propriétés● Principales propriétés supplémentaires
● inputType : permet d'ajouter un filtre de saisie : email, mot de passe, numérique, multi-lignes, …– pas de validation, affiche le clavier adéquat, filtre les touches
● scrollHorizontally : défilement horizontal du texte si celui-ci est plus grand que la zone de saisie
● La méthode getText() permet de récupérer le texte saisi
antislashn.org Android - composants graphiques de base 5 - 52/56
EditText<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >
... <EditText android:id="@+id/nom" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPersonName" />
...
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" >
</EditText>
... <EditText android:id="@+id/email" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textEmailAddress" > </EditText>
</LinearLayout>
Listing incomplet
antislashn.org Android - composants graphiques de base 5 - 53/56
Button
● Des actions sont souvent utilisés avec le widget Button● de manière générale des actions sont utilisables sur
tous les widgets● Hérite de TextView
● propriétés utiles– onClick : nom de la méthode de l'activité à exécuter
● la signature de la méthode doit être:– public void nomMethode(View vue);
antislashn.org Android - composants graphiques de base 5 - 54/56
Button
● Java peut aussi être utiliser pour lier l'action au bouton● appel de listener
– même type de programmation événementielle que Swing● la mise en place du listener se fait par la méthode
– public void setOnClickListener(View.OnClickListener listener)
– même choix d'implémentation que sous Swing● doit implémenter View.OnClickListener
– classe anonyme– méthode de l'activité– méthode d'une classe de traitement
– l'implémentation doit fournir une méthode● public void onClick(View v)
antislashn.org Android - composants graphiques de base 5 - 55/56
Button
● Mise en place de l'action par le fichier XML● listings incomplets
<Button android:id="@+id/btnEnvoyer" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Envoyer" android:onClick="enregistrerUtilisateur" />
public void enregistrerUtilisateur(View v){ Button b = (Button) v; EditText nom = (EditText) this.findViewById(R.id.nom); Toast.makeText(this, b.getText()+"\n"+ nom.getText(),
Toast.LENGTH_LONG).show(); }
création et affichage d'un toast
rendu du toast
antislashn.org Android - composants graphiques de base 5 - 56/56
Button
● Exécution de l'action par utilisation d'un listener● listings incomplets
<Button android:id="@+id/btnEnvoyer" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Envoyer" />
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final Button b = (Button) findViewById(R.id.btnEnvoyer); b.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) { EditText nom = (EditText) findViewById(R.id.nom); Toast.makeText(v.getContext(), "Bonjour "+ nom.getText(),
Toast.LENGTH_LONG).show();}
});}
création d'une classe anonyme
antislashn.org Android - Intent 6 - 2/28
Bus de messages● Les modules applicatifs ne sont pas invoqués directement
● ils sont activés via des messages, les "intentions"– classe Intent
● Le message contient la description de l'opération devant être exécutée● sous forme divers
– nom de la classe– action sous forme de chaîne de caractère– type MIME
● Les messages sont aussi utilisés pour les retours de résultats entre modules
antislashn.org Android - Intent 6 - 3/28
Bus de messages
Producteur
Système AndroidModule applicatif
Intent
IntentResolver
Application 2
Activité
Activité
IntentFilter
IntentFilter
Application 1
Activité
Service
IntentFilter
IntentFilter
Le composant dont le filtred'intention correspond estactivé
antislashn.org Android - Intent 6 - 4/28
Bus de messages● Activation d'activité
● Context.startActivity() ● Context.startActivityForResult()
– un intention est associée à Activity.setResult()
● Activation de service● Context.startService()● Context.bindService()
● Activation de BroadcastReceiver● Context.sendBroadcast()● Context.sendOrderedBroadcast()● Context.sendBroadcast()
antislashn.org Android - Intent 6 - 5/28
Bus de messages● La collaboration entre les applications s'effectue via un
bus de message● une instance de Intent est le message
● Contient plusieurs champs● nom du composant qui doit gérer l'Intent● l'action qui doit être exécutée
– sous forme de String
● une donnée sous forme d'URI et de type MIME● une catégorie qui correspond au type de composant devant
gérer l'Intent● des données supplémentaires – les Extras● des flags utilisés par Android pour gérer le mode de
chargement d'une activité
antislashn.org Android - Intent 6 - 6/28
Bus de messages
Activité principale
Activité A
Intent de lancement
Intent de résultat
Activité BIntent de lancement
extra
antislashn.org Android - Intent 6 - 7/28
Lancement d'un message
● Selon le mode d'instanciation d'un Intent, les champs précédents peuvent être nuls.
● Deux groupes de messages● les intentions explicites
– le composant à activé est désigné par son nom– en général utilisés au sein d'une même application
● les intentions implicites– le nom du composant à activer n'est pas connu– permet d'activer des composants d'autres application
antislashn.org Android - Intent 6 - 8/28
Intent
● Intention explicite● le composant cible est connu
– souvent une activité de la même application– le composant cible n'a pas besoin de déclarer de filtre
d'intention dans le manifeste● seulement des iintentions explicites peuvent alors l'invoquer
● syntaxe● public Intent(Context ctx, Class<?> cls)● public Intent(String action, Context ctx, Class<?> cls)
Intent intent = new Intent(this,ExplicitActivity.class);startActivity(intent);
antislashn.org Android - Intent 6 - 9/28
Intent
● Intention implicite● le composant destinataire n'est pas connu● le système est chargé de trouver le composant
destinataire– si plusieurs composants cibles existent, le système demande
à l'utilisateur de choisir● création d'une intention implicite
– l'action est positionnée– une donnée associée (URI) peut être ajoutée
● syntaxe● public Intent(String action)● public Intent(String action, Uri uri)
antislashn.org Android - Intent 6 - 10/28
Intent
● Intention implicite● exemple
– le système cherche alors le meilleur composant parmi ceux ayant déclarés leur capacité à réaliser l'action
● les composants ayant la capacité de réaliser l'action doivent déclarer un filtre d'intentions– un filtre d'intention n'a aucune incidence sur les
intentions explicites
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:0102030405"));
antislashn.org Android - Intent 6 - 11/28
Résolution des intentions● Pour les intentions implicites Android doit trouver le – ou
les – composants susceptibles de gérer l'intention● L'objet Intent est comparé aux filtres d'intentions
déclarés par les composants prenant en charge le message● dans le fichier manifeste● balise <intent-filter>
● Trois champs sont retenus pour ce test● l'action● la donnée : URI et type MIME● la catégorie
antislashn.org Android - Intent 6 - 12/28
Résolution des intentions
● Test sur l'action● le test échoue si le filtre ne contient pas l'action de
l'intention● Test sur la catégorie
● chacune des catégories de l'intention doit correspondre aux catégories du filtre
● toutes les catégories du filtre n'ont pas a être présentes dans l'intention
● un objet Intent qui ne possède pas de catégorie passera donc toujours ce test– une exception : le démarrage d'une activité nécessite la
catégorie android.intent.category.DEFAULT
antislashn.org Android - Intent 6 - 13/28
Résolution des intentions
● L'élément <data> spécifie une URI et un type MIME● l'URI est constituée de schema, host, port et path
– schema://host:port/path– host:port forme l'authority
● Test sur la donnée● un Intent qui ne contient pas de data passe le test● un Intent qui contient une URI sans type de donnée
passe le test si le filtre correspond● un Intent qui contient un type MIME passe le test si le
type correspond
antislashn.org Android - Intent 6 - 14/28
Résolution des intentions
● Utilisation des types MIME● par défaut l'application SMS Android récupère
l'ensemble des intentions sur les types MIME● il faut associer une action propre au composant pour
filtrer sur le type MIME et l'action● Si plusieurs modules applicatifs peuvent répondre
à l'intention, Android présente une boite de dialogue de choix à l'utilisateur
antislashn.org Android - Intent 6 - 15/28
Intent
● La méthode getIntent() permet de récupérer l'intention ayant lancée le composant
● L'action d'une intention peut être mise à jour et récupérée par● public Intent setAction(String action)● public String getAction()
● Des données supplémentaires peuvent être fournies à l'intention, sous forme de● de catégories● de données● d'extras
antislashn.org Android - Intent 6 - 16/28
Intent
● La catégorie● utilisée pour déterminer le type de composant qui doit
réaliser l'action● ajout par la méthode
– public Intent addCategory(String category)
● le paramètre String décrit la catégorie● Android définie un certains nombre de catégories,
comme CATEGORY_LAUNCH, CATEGORY_HOME– cf. la documentation
antislashn.org Android - Intent 6 - 17/28
Intent
● Les données● regroupe l'URI et le type MIME de la données cible● le format et la signification des données sont
dépendants de l'action spécifiée● en général le type MIME peut être déduit de l'URI● méthodes utiles
– public Intent setData(Uri data)– public Uri getData()– public Intent setType(String type)– public String getType()
● l'utilisation de setData et setType sont concurrentes, elles écrasent leurs données respective
antislashn.org Android - Intent 6 - 18/28
Intent
● Filtre d'intentions● balise XML : intent-filter
– balise fille de la balise de déclaration du composant applicatif– attributs
● icon : affichage pour l'utilisateur● label : affichage pour l'utilisateur● priority : donne une priorité de choix auprès du système, la valeur
la plus forte est la plus prioritaire
● balises filles principales– action : nom de l'action sur laquelle réagir
– category : nom de la catégorie sur laquelle réagir
– data : spécifie une URI et/ou un type MIME
antislashn.org Android - Intent 6 - 19/28
Résolution des intentions
● Un composant applicatif peut déclarer plusieurs filtres d'intention
<activity android:name=".Activity2"> <intent-filter > <action android:name="org.antislashn.android.action.TOTO" /> <category android:name="android.intent.category.DEFAULT"/> <category android:name="org.antislashn.android.category.LAUNCH"/> </intent-filter> <intent-filter > <action android:name="org.antislashn.android.action.TOTO" /> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="moncontent" android:host="org.antislashn.android"
android:port="150"/> </intent-filter> <intent-filter > <action android:name="org.antislashn.android.action.TOTO" /> <category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="type/antislashn"/> </intent-filter> </activity>
nécessaire pour lancer l'activité
antislashn.org Android - Intent 6 - 20/28
Résolution des intentions
● Filtre avec action et catégorie
● appel avec action
● appel avec action et catégorie
<intent-filter > <action android:name="org.antislashn.android.action.TOTO" /> <category android:name="android.intent.category.DEFAULT"/> <category android:name="org.antislashn.android.category.LAUNCH"/></intent-filter>
Intent intent = new Intent(Activity2.ACTION);startActivity(intent);
défini l'action TOTO
Intent intent = new Intent(Activity2.ACTION);intent.addCategory(Activity2.LAUNCH_CATEGORY);startActivity(intent);
défini l'action TOTO
défini la catégorie LAUNCH
antislashn.org Android - Intent 6 - 21/28
Résolution des intentions
● Filtre avec action et URI
● appel
<intent-filter > <action android:name="org.antislashn.android.action.TOTO" /> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="moncontent" android:host="org.antislashn.android"
android:port="150"/></intent-filter>
Uri uri = Uri.parse("moncontent://org.antislashn.android:150/exemple/toto");Intent intent = new Intent(Activity2.ACTION,uri);startActivity(intent);
antislashn.org Android - Intent 6 - 22/28
Résolution des intentions
● Filtre avec action et type MIME
● appel
<intent-filter > <action android:name="org.antislashn.android.action.TOTO" /> <category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="type/antislashn"/> </intent-filter>
Intent intent = new Intent(Activity2.ACTION);intent.setType("type/antislashn");startActivity(intent);
antislashn.org Android - Intent 6 - 23/28
Intent
● Exemples d'utilisation d'intentions● utilisation d'une action et d'une URI
– ACTION_VIEW et content://contacts/people/1● affichera les informations du contact ayant l'identifiant 1
– ACTION_DIAL et tel:123● provoque l'affichage du clavier téléphonique avec le numéro de
téléphone– ACTION_GET_CONTENT et vnd.android.cursor.item/phone
● affiche la liste des numéros de téléphone
● autres exemples– ACTION_MAIN et CATEGORY_HOME
● affichage de l'écran d'accueil
antislashn.org Android - Intent 6 - 24/28
Intent
● Les Extras● données applicatives ajoutées à l'intention● méthodes
– public Intent putExtras(Bundle extra)– public Bundle getExtras()
antislashn.org Android - Intent 6 - 25/28
Intent
● Bundle● similaire à la classe Map
– clé : uniquement de type String– valeur associée à la clé : toute instance, ou tableau
d'instances, de classe implémentant l'interface Parcelable● mécanisme de sérialisation léger propre à Andoid
● de nombreuses méthodes de la classe Intent permettent de ne pas instancier directement un Bundle
– public Intent putExtra(String name, int value)
– public int getIntExtra(String name, int defaultValue)
– public Intent putExtra(String name, String value)
– public String getStringExtra(String name, String defaultValue)
– etc.
antislashn.org Android - Intent 6 - 26/28
Intent
● Des indicateurs (flags, drapeaux) peuvent aussi être ajouter à l'intention● public Intent setFlags(int flags)● public Intent addFlags(int flags)● public int getFlags()
● Les flags permettent de changer certains comportements par défaut des activité● gestion de la pile des activités par exemple
antislashn.org Android - Intent 6 - 27/28
PendingIntent
● Intention en attente● de type PendingIntent● contient une instance d'Intent décrivant l'action à
réaliser● cette action est réalisée ultérieurement
– par une autre application qui reçoit alors les droits de l'application qui a créée l'intention en attente
● création d'une intention en attente par les méthodes statique de PendingIntent– getActivity : lancera une activité
– getService : lancera un service
– getBroadcast : diffuse un événement
antislashn.org Android - Intent 6 - 28/28
PendingIntent
● Avec un Intent, un module applicatif A demande le lancement d'un module applicatif B
● Avec un PendingIntent, un module applicatif A demande à un module X de lancer un module B
Activité A Activité BIntent
Activité A Module X Activité BIntentPendingIntent
antislashn.org Android - Activity 7 - 2/22
Activity
● Composant applicatif● peut-être constitué de fragments (Fragment)
– sera abordé plus loin● représente la gestion d'un écran pour l'utilisateur
– une application simple peut être composée d'une seule activité
– l'écran géré par l'activité est celui qui est vu par l'utilisateur● s'exécute dans le thread principal de l'application
– ne pas bloquer ce thread principal par des calculs ou attentes de ressources
● mauvaise expérience utilisateur● Android peut alors décider de tuer l'activité
antislashn.org Android - Activity 7 - 3/22
Activity
● Une activité spécialise la classe Activity● Activity hérite de Context● l'activité est déclarée dans le fichier manifeste
● Possède un cycle de vie qui est géré par Android● nous avons vu la méthode onCreate(...)
● Une activité est déclenchée par une intention (Intent)● intention implicite● intention explicite
antislashn.org Android - Activity 7 - 4/22
Activity
● Activités et intentions● une activité qui accepte des intentions implicites doit
déclarer dans ses filtres d'intention la catégorie– android.intent.category.DEFAULT
● une activité qui est le point d'entrée de l'application doit déclarer– l'action : android.intent.action.MAIN
● composant point d'entrée de l'application
– la catégorie : android.intent.category.LAUNCHER● composant pouvant être lancé par l'utilisateur
– la combinaison MAIN et LAUNCHER ajoutera l'activité au "Lanceur d'applications" Android
– ne déclare pas android.intent.category.DEFAULT
antislashn.org Android - Activity 7 - 5/22
Activity
● Déclaration dans le manifeste● attributs courants
– label : nom de l'activité, si non précisé le label de l'application est utilisé
– icon : icône de l'activité, si non précisé l'icône de l'application est utilisé
– name : spécifie la classe de l'activité, si le package est le même que l'attribut package de la balise manifest, il peut être remplacé par point (.).
– screenOrientation : orientation de l'écran que doit adopter l'application
● pas recommandé de fixer cette valeur
– hardwareAcceleration : (depuis API 11) demande d'amélioration des performances d'affichage
antislashn.org Android - Activity 7 - 6/22
Activity
● Exemple de fichier manifeste<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.antislashn.android.activity" android:versionCode="1" android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".AppelactivityActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:label="explicit" android:name=".ExplicitActivity" > </activity> </application></manifest>
activité point d'entrée de l'application
activité ne pouvant être appelée que par un intent explicite
antislashn.org Android - Activity 7 - 7/22
Activity
● Cycle de vie● une activité peut-être détruite par le système à partir du
moment ou cette activité est en pause● les différentes méthodes du cycle de vie peuvent être
surchargées– il faut commencer par appeler la méthode du même nom dans
la classe mère● exemple : super.onCreate(savedInstanceState)
● bien garder à l'esprit que l'activité peut être exécutée en arrière plan– l'activité est toujours en mémoire, mais pas d'affichage
antislashn.org Android - Activity 7 - 9/22
Activity
● onCreate● appelée à la création de l'activité● un seul appel lors du cycle de vie● permet de créer les IHM, initialiser l'activité, …● reçoit un objet de type Bundle
– récupère des informations sauvegardées précédemment lors de la dernière exécution
– la sauvegarde est faite par le système● une fermeture normale de l'activité ne provoque pas de sauvegarde● si Android ferme l'activité la sauvegarde est effectuée
– les méthodes onSaveInstance et onRestoreInstance permettent d'ajouter des objets dans Bundle
● ne pas utiliser pour la persistance, car onSaveInstance n'est pas toujours appelée (arrêt normal de l'application par exemple)
antislashn.org Android - Activity 7 - 10/22
Activity
● onStart● appelée après la méthode onCreate ou onRestart● précède l'affichage de la vue de l'activité
● onResume● appelée après la méthode onStart ou onPause● après l'affichage de la vue de l'activité
antislashn.org Android - Activity 7 - 11/22
Activity
● onPause● appelée lorsque une autre activité prend la main pour
passer en premier plan● l'exécution de la méthode doit être rapide● sauvegarde des données persistantes, arrêt des tâches
consommatrices de ressources, …● la méthode isFinishing() permet de savoir si
l'activité va être détruite ou juste mise en pause● jusqu'à l'API 11 Android peut décider de tuer
l'application à partir de la sortie de cette méthode● à partir de l'API 11 Android peut décider de tuer
l'application après onStop
antislashn.org Android - Activity 7 - 12/22
Activity
● onStop● permet de libérer certaines ressources● jusqu'à l'API 11 l'appel de cette méthode peut ne jamais
être exécutée● onRestart
● appelée si l'activité revient au premier plan● suivi d'un appel à onStart
● onDestroy● appelée après un appel de la méthode finish ou par le
système si celui-ci à besoin de ressources● permet de libérer des ressources liées à l'activité
antislashn.org Android - Activity 7 - 13/22
Activity
● Des méthodes événementielles permettent de gérer la persistance de l'instance● onSaveInstanceState(Bundle) qui est appelée
juste avant que l'activité soit tuée onDestroy()● onRestoreInstanceState(Bundle) qui est
appelée après la méthode onStart() et avant onPostCreate(Bundle)
antislashn.org Android - Activity 7 - 14/22
Activity
● lancement d'une activité par la méthode startActivity
● public void startActivity(Intent intent)● l'intention peut-être explicite ou implicite
● si l'activité invoquée doit retourner un résultat● appeler l'activité avec startActivityForResult● coder une méthode callback onActivityResult
antislashn.org Android - Activity 7 - 15/22
Activity
● startActivityForResult● public void startActivityForResult(Intent intent,
int requestCode)
● paramètres– intent : intention envoyée au sysème
– requestCode : si >=0, ce même code sera retourné à la méthode onActivityResult
–
antislashn.org Android - Activity 7 - 16/22
Activity
● onActivityResult● public void onActivityResult(int requestCode,
int resultCode,Intent data)
● paramètres– requestCode : code utilisé dans startActivityForResult
– resultCode : résultat de retour de l'activité● ce code a été positionné par l'activité par la méthode setResult(int)ou setResult(int,Intent)
– data : intention retournée par l'activité, ce qui permet de récupérer les extras ajoutés à l'intention par l'activité
● ce code a été positionné par l'activité appelée via sa méthode setResult(int,Intent)
antislashn.org Android - Activity 7 - 17/22
Activity
● Résumé : appel d'une activité avec retour de résultat● dans l'activité appelante
– coder la méthode onActivityResult
– lancer l'intention pour démarrer l'activité appelée, celle qui retourne le résultat
● dans l'activité appelée– avant de finir l'activité, créer un nouvel Intent
– ajouter un extra
– ajouter à setResult
– puis appeler finish()
● au retour, dans l'activité appelée– récupérer l'intention et extraire l'extra
antislashn.org Android - Activity 7 - 18/22
Activity
● Exemple de code● activité appelante
public class ActivityResultActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void appelAutreActivity(View v){ Intent intent = new Intent(this,AutreActivity.class); startActivityForResult(intent, 0); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data){ int r = data.getIntExtra("resultat", 0); Toast.makeText(this, "RESULTAT = "+r, Toast.LENGTH_LONG).show(); }}
appel de l'activité devant retournerun résultat
récupération du résultat préparé parl'activité appelée
antislashn.org Android - Activity 7 - 19/22
Activity
● Exemple de code● activité appelée retournant le résultat
public class AutreActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.autre_activity); } public void stopActivity(View v){ Intent intent = new Intent(); intent.putExtra("resultat", 10); this.setResult(0, intent); this.finish(); }}
préparation du résultat renvoyé àl'activité appelante
antislashn.org Android - Activity 7 - 20/22
Activity
● A chaque application le système associe une pile LIFO● la pile d'activités● empile les activités lancées les une après les autres● le bouton retour dépile les activités● si l'utilisateur revient sur la page d'accueil Android
(touche Accueil) la pile est sauvegardée– elle est restituée lorsque l'application est relancée– l'activité courante est donc retrouvée
antislashn.org Android - Activity 7 - 21/22
Activity
● Il est possible de changer le mode de fonctionnement par défaut de la pile● utilisation des attributs de la balise activity
– alwaysRetainTaskState : (yes | no)
– clearTaskOnLaunch : (yes | no)
– finishOnTaskLauch : (yes | no)
– launchMode : (standard | singleTop | singleTask | singleInstance)
● ajout du flag Intent.FLAG_ACTIVITY_CLEAR_TOP pour dépiler la pile jusqu'à l'activité qui doit être lancée
antislashn.org Android - Activity 7 - 22/22
Activity
● Des classes dérivées de Activity permettent de simplifier la gestion de certains contrôles graphiques● ListActivity● MapActivity● AccountAthentificationActivity● ...
antislashn.org Android - ListView 8 - 2/29
Widgets de sélection
● Les cases à cocher ou boutons radio permettent des sélection sur un petit groupe d'items
● Si la sélection doit être effectuée sur un nombre d'items plus large d'autres composants graphiques sont plus appropriés● Spinner, Gallery, ListView, ...● peuvent afficher plus d'informations
antislashn.org Android - ListView 8 - 3/29
Widgets de sélection
● Le développement autour de ces widgets utilise● des layouts spécifiques
– Android fournit des layouts de base– nous pouvons développer les nôtres
● des adaptateurs de données– permet de remplir le composant graphique avec le contenu
d'une source de données● tableau, liste, base de données
antislashn.org Android - ListView 8 - 4/29
Widgets de sélection
DONNEES
Adaptateur
ligne de données
liaison et mise en forme des données
antislashn.org Android - ListView 8 - 5/29
ListView
● Composant graphique permettant de représenter des listes d'items● composant important● permet à l'utilisateur de choisir un item● est muni d'un ascenseur● la vue est de type ListView● la ListView peut est gérée par
une activité● il est préférable d'utiliser la classe ListActivity– et ListFragment depuis Android 3.0
antislashn.org Android - ListView 8 - 6/29
ListView
● Une vue ListView est constituée de lignes● ListView est de type ViewGroup● chaque ligne est une vue enfant du ViewGroup
– prend en charge l'affichage des données d'un élément de la liste
● Les données à afficher sont de provenance divers● la liste utilise un ListAdpater
– lie la vue aux données
● Android fournit plusieurs ListAdapter– ArrayAdapter<T> pour les données de type tableau
– CursorAdapter pour les données stockées en base
– SimpleCursorAdapter pour les données de type String ou image stockées en base
– etc.
antislashn.org Android - ListView 8 - 7/29
ListView
● ListView peut être géré par une activité● ListActivity simplifie la gestion de l'activité en
fournissant des méthodes support● récupère une ListView depuis les ressources layout
– doit être identifiée par @android:id/list
● La liaison d'une liste avec les données à afficher est effectué par un adaptateur● de type Adapter
– ListAdapter, SimpleAdapter et SimpleCursorAdapter
– comme le Spinner
antislashn.org Android - ListView 8 - 8/29
ListView
● Chaque adaptateur possède son constructeur propre
● La classe ListView possède une méthode setAdapter(...) qui lie la vue avec les données● si l'activité hérite de ListActivity, la méthode est
dans l'activité– en cas d'utilisation des layout par défaut l'identifiant de la ListView doit être android:id/list
<ListView android:id="@+android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView>
antislashn.org Android - ListView 8 - 9/29
ListView
● Exemple avec ArrayAdapter<T>● Android fournit des gestionnaire de positionnement par
défaut (l'identifiant de la liste doit être android:id/list)– android.R.layout.simple_list_item_1 qui comprend un
objet unique de type TextView
– android.R.layout.simple_list_item_2 qui comprend deux objets de type TextView, le second en dessous du premier dans une taille plus petite
public class ListViewActivity01 extends ListActivity {
private static final String[] items = {"item 1","item 2","item 3","item 4"};
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,items); setListAdapter(adapter); } }
antislashn.org Android - ListView 8 - 10/29
ListView
● Exemple d'utilisation de rendu avec le layout par défaut android.R.simple_list_item_1
antislashn.org Android - ListView 8 - 11/29
ListView
● Utilisation du layout par défaut android.R.simple_list_item_2● ce layout par défaut utilise un adaptateur qui relie une Map<String,?> avec deux TextView, appelés text1 et text2
● il faut utiliser un adaptateur adéquat– ArrayAdapter ne possède qu'un seul champ de type texte
– nous utilisons un SimpleAdapter qui est construit avec● le contexte● la liste de type List<Map<String,?>> ou la clé correspond
respectivement à la ligne 1 puis 2● le layout simple_list_item_2● les clés des deux lignes sous forme de String[]● les deux identifiants de TextView sous forme de int[]
antislashn.org Android - ListView 8 - 12/29
ListView
● Exemple d'utilisation du layout par défaut android.R.simple_list_item_2
public class ListView02Activity extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); List<HashMap<String, String>> liste = new ArrayList<HashMap<String,String>>(); String[] from = {"line 1","line 2"}; int[] to = {android.R.id.text1,android.R.id.text2}; HashMap<String, String> map = new HashMap<String, String>(); map.put("line 1","Item 1"); map.put("line 2", "Sub item 1"); liste.add(map); map.put("line 1","Item 2"); map.put("line 2", "Sub item 2"); liste.add(map); SimpleAdapter adapter = new SimpleAdapter(this,liste,android.R.layout.simple_list_item_2,from, to); setListAdapter(adapter); } }
antislashn.org Android - ListView 8 - 13/29
ListView
● Exemple de rendu avec le layout par défaut android.R.simple_list_item_2
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >
<ListView android:id="@+android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView>
</LinearLayout>
antislashn.org Android - ListView 8 - 14/29
ListView
● Lors de l'ajout/suppression d'items dans collection il faut appeler la méthode notifyDataSetChange de l'adaptateur pour que les changements soient pris en compte dans la vue● si l'adaptateur gère les ajouts et suppressions de
données cet appel n'est pas nécessaire
antislashn.org Android - ListView 8 - 15/29
ListView
● La gestion de l'événement sur une ligne du ListView s'effectue par un l'utilisation d'un listener● AdapterView.OnItemClickListener
– méthode onItemClickListener● paramètres
– AdapterView<?> parent : adaptateur– View view : vue de la ligne– int position: position de la ligne
antislashn.org Android - ListView 8 - 16/29
ListView
● Exemple de code d'implémentation du listener
@Overridepublic void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
Toast.makeText(getApplicationContext(), ((TextView) view).getText(),Toast.LENGTH_SHORT).show();}
antislashn.org Android - ListView 8 - 17/29
ListView – layout personnalisé
● Nous allons afficher les propriétés d'une classe● title et text de la classe Item
public class Item {private int id;private String title;private String text;
public Item() {}public Item(int id, String title, String text) {
this.id = id;this.title = title;this.text = text;
}public int getId() {
return id;}
...
public void setText(String text) {this.text = text;
}}
antislashn.org Android - ListView 8 - 18/29
ListView – layout personnalisé
● Une classe support, ItemDAO, permet de créer et récupérer la liste d'Item
public class ItemDAO {private List<Item> items = new ArrayList<Item>();
public ItemDAO(){items.add(new Item(1,"item 1","Faire item 1"));items.add(new Item(2,"item 2","Faire item 2"));items.add(new Item(3,"item 3","Faire item 3"));items.add(new Item(4,"item 4","Faire item 4"));items.add(new Item(5,"item 5","Faire item 5"));
}
public List<Item> getAllItems(){return items;
}}
antislashn.org Android - ListView 8 - 19/29
ListView – layout personnalisé
● Le layout personnalisé est décrit dans un fichier XML, dans res/layout● fichier item.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:id="@+id/LL_item">
<TextView android:text="title" android:id="@+id/item_title"
android:layout_width="wrap_content" android:layout_height="wrap_content"android:textColor="@android:color/black" />
<TextView android:text="texte" android:id="@+id/item_texte"
android:layout_width="wrap_content" android:layout_height="wrap_content"android:textColor="@android:color/black" />
</LinearLayout>
antislashn.org Android - ListView 8 - 20/29
ListView – layout personnalisé
● Il faut créer son propre adaptateur pour faire le lien en la ListView et l'affichage de chaque ligne● ItemAdapter spécialise BaseAdapter● le constructeur recevra
– le contexte– la liste contenant les Items
● méthodes à redéfinir– int getCount() : renvoie le nombre d'objets de la collection
– Object getItem(int pos) : renvoi un objet en fonction de sa position
– long getItemId(int pos) : renvoie l'identifiant de l'objet en fonction de sa position
– View getView(...) : renvoie la vue construite pour une position
antislashn.org Android - ListView 8 - 21/29
ListView – layout personnalisé
● paramètres de getView(...)● int position : position de la ligne du ListView à
afficher● View convertView : vue de la ligne à réutilisée
– si null c'est que la vue n'a pas été créée– si la vue n'est pas nulle alors la réutiliser
● View parent : vue parente
antislashn.org Android - ListView 8 - 22/29
ListView – layout personnalisé
● Code de l'adaptateur ItemAdapterpublic class ItemAdapter extends BaseAdapter {
private List<Item> items;private Context context;private LayoutInflater layoutInflater;
public ItemAdapter(Context context, List<Item> listItems){this.items = listItems;this.context = context;this.layoutInflater = LayoutInflater.from(context);
}
@Overridepublic int getCount() {
return items.size();}
@Overridepublic Object getItem(int position) {
return items.get(position);}
@Overridepublic long getItemId(int position) {
return items.get(position).getId();}
...
antislashn.org Android - ListView 8 - 23/29
ListView – layout personnalisé
● Code de l'adaptateur ItemAdapter...
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {
LinearLayout layoutItem; if (convertView == null) { layoutItem = (LinearLayout) layoutInflater.inflate(R.layout.item, parent, false); } else { layoutItem = (LinearLayout) convertView; } TextView title = (TextView)layoutItem.findViewById(R.id.item_title); TextView texte = (TextView)layoutItem.findViewById(R.id.item_texte);
title.setText(items.get(position).getTitle()); texte.setText(items.get(position).getText()); if (position % 2 == 0) { layoutItem.setBackgroundColor(Color.WHITE); } else { layoutItem.setBackgroundColor(Color.LTGRAY); } return layoutItem;
}}
réutilisation du layout
initialisation du layout
récupération des TextView
mise à jour des TextView
coloration des lignes
retour du layout
antislashn.org Android - ListView 8 - 24/29
ListView – layout personnalisé
● Il faut maintenant utiliser notre layout
public class ListView03Activity extends ListActivity {private static ItemDAO dao = new ItemDAO();
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ItemAdapter adapter = new ItemAdapter(this, dao.getAllItems()); setListAdapter(adapter); }}
antislashn.org Android - ListView 8 - 25/29
ListView – layout personnalisé
● Ajout d'un bouton sur la ligne de l'item
antislashn.org Android - ListView 8 - 26/29
ListView – layout personnalisé
● Le fichier XML du layout évolue<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:stretchColumns="0" >
<TableRow > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" >
<TextView android:id="@+id/item_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="title" /> <TextView android:id="@+id/item_texte" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="texte" /> </LinearLayout>
<ImageButton android:id="@+id/imageButton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:onClick="deleteItem" android:src="@android:drawable/btn_star" /> </TableRow></TableLayout>
méthode invoquée lors d'un clicsur le bouton
antislashn.org Android - ListView 8 - 27/29
ListView – layout personnalisé
● Il faut récupérer dans l’événement de l'activité le bon widget par rapport au clic sur le bouton
● Pour gérer le clic sur le titre de l'Item, en récupérant l'objet Item, il suffit de créer une interface listener● le listener sera ajouté à l'adaptateur
public void deleteItem(View v){TableRow tr = (TableRow) v.getParent();TextView tv = (TextView) ((LinearLayout)tr.getChildAt(0)).getChildAt(0);Toast.makeText(this, tv.getText(), Toast.LENGTH_SHORT).show();
}
public interface ItemAdapterListener {public void onClick(Item item, int position);
}
antislashn.org Android - ListView 8 - 28/29
ListView – layout personnalisé
● C'est l'adaptateur qui appel la méthode callback du listener enregistré● extrait du codepublic void setItemAdapterListener(ItemAdapterListener itemAdapterListener) {
this.itemAdapterListener = itemAdapterListener;}
@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {
LinearLayout layoutItem;
...
title.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if(itemAdapterListener!=null)
itemAdapterListener.onClick(items.get(position), position);}
});return layoutItem;
}
ajout d'un listener sur le TextView dont laméthode callback invoque la méthode callbackdu listener personnalisé
antislashn.org Android - ListView 8 - 29/29
ListView – layout personnalisé
● Il faut que l'activité réagisse au clic sur le titre de l'item
public class ListView03Activity extends ListActivity implements ItemAdapterListener{private static ItemDAO dao = new ItemDAO();
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ItemAdapter adapter = new ItemAdapter(this, dao.getAllItems()); setListAdapter(adapter); adapter.setItemAdapterListener(this); }
@Overridepublic void onClick(Item item, int position) {
Toast.makeText(this, item.toString(), Toast.LENGTH_SHORT).show();}
}
l'activité implémente ItemAdapterListeneret s'ajoute auprès de l'adaptateur
comportement au clic sur le titre de l'item
antislashn.org Android - Autres composants graphiques 9- 2/33
ImageButton
● Tout simplement un bouton avec une image
<ImageButton android:id="@+id/imageButton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:src="@drawable/image" android:onClick="clic" android:soundEffectsEnabled="true" android:hapticFeedbackEnabled="true" />
antislashn.org Android - Autres composants graphiques 9- 3/33
ToggleButton
● Bouton à deux états● activé ou non (checked)● non activé par défaut
● Hérite de Button● Attributs utiles
● textOn : texte affiché dans l'état activé● textOff : texte affiché dans l'état désactivé
● Méthodes utiles● public void setChecked(boolean state)● boolean isChecked()
● Comme pour Button il est fréquent d'utiliser une action sur le clic
antislashn.org Android - Autres composants graphiques 9- 4/33
ToggleButton
● Exemple<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >
<ToggleButton android:id="@+id/toggleButton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textOn="@string/messageTbOn" android:textOff="@string/messageTbOff"/>
</LinearLayout>
antislashn.org Android - Autres composants graphiques 9- 5/33
CheckBox
● Case à cocher● possède deux états : coché ou non● les cases à cocher sont indépendantes entre elles
– contrairement aux RadioButton d'un même groupe
antislashn.org Android - Autres composants graphiques 9- 6/33
CheckBox
● Case à cocher● possède deux états : coché ou non● les cases à cocher sont indépendantes entre elles
– contrairement aux RadioButton d'un même groupe
antislashn.org Android - Autres composants graphiques 9- 7/33
CheckBox
● Exemple : fichier XML● suite page suivante
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >
<CheckBox android:id="@+id/cbVibreur" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Vibreur" android:tag="vibreur"/>
</LinearLayout>
antislashn.org Android - Autres composants graphiques 9- 8/33
CheckBox
● Exemple : fichier Java
public class CheckBoxActivity extends Activity implements View.OnClickListener { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); CheckBox cb = (CheckBox) findViewById(R.id.cbVibreur); cb.setOnClickListener(this); }
@Overridepublic void onClick(View v) {
CheckBox cb = (CheckBox) v; String message = (String) cb.getTag(); if(cb.isChecked()){ message += " est coché"; } else{ message += " est décoché"; } Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}}
antislashn.org Android - Autres composants graphiques 9- 9/33
RadioButton
● Boutons radios● sont regroupés dans un RadioGroup
– permet d'avoir le caractère exclusif d'une seule sélection
● Sous Eclipse● utiliser le widget RadioGroup● puis supprimer ou ajouter des RadioButton
antislashn.org Android - Autres composants graphiques 9- 10/33
RadioButton
● Exemple● extrait du fichier XML
<RadioGroup android:id="@+id/radioGroup1" android:layout_width="wrap_content" android:layout_height="wrap_content">
<RadioButton android:id="@+id/radio0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="Java" android:onClick="afficherSelection" />
... <RadioButton android:id="@+id/radio2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Python" android:onClick="afficherSelection"/></RadioGroup>
antislashn.org Android - Autres composants graphiques 9- 11/33
RadioButton
● Exemple● fichier Java
public class RadioButtonActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("RadioButtonActivity", "Fin onCreate()"); setContentView(R.layout.main); } public void afficherSelection(View v){ RadioButton rd = (RadioButton) v; Toast.makeText(this, rd.getText(), Toast.LENGTH_SHORT).show(); }}
antislashn.org Android - Autres composants graphiques 9- 12/33
RadioGroup
● Il est souvent plus simple de traiter l’événement sur le RadioGroup que sur chaque RadioButton● événement onCheckedChanged● voir l'exemple suivant
● Certaines méthodes de RadioGroup permettent de gérer la sélection des RadioButton● check(int id), clearCheck()● cf. la documentation
antislashn.org Android - Autres composants graphiques 9- 13/33
RadioGroup
● Exemple● fichier XML
<RadioGroup android:id="@+id/radioGroup1" android:layout_width="wrap_content" android:layout_height="wrap_content">
<RadioButton android:id="@+id/radio0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="Java"/>
...
<RadioButton android:id="@+id/radio2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Python"/></RadioGroup>
antislashn.org Android - Autres composants graphiques 9- 14/33
RadioGroup
● Exemple● fichier Java
public class RadioGroupActivity extends Activity implements RadioGroup.OnCheckedChangeListener{
/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); RadioGroup rg = (RadioGroup) findViewById(R.id.radioGroup1); rg.setOnCheckedChangeListener(this); }
@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton rb = (RadioButton) findViewById(checkedId);Toast.makeText(this, "Langage : "+rb.getText(), Toast.LENGTH_SHORT).show();
}}
antislashn.org Android - Autres composants graphiques 9- 15/33
Spinner
● Équivalent d'une boite déroulante● une boite de sélection des éléments apparaît lors du
choix
antislashn.org Android - Autres composants graphiques 9- 16/33
Spinner
● Un adaptateur de données doit être fournit au Spinner● découplage de la vue et des données à afficher
– comme pour le ListView
● méthode setAdapter(...) du Spinner● les adaptateurs permettent de gérer les données provenant
– d'un tableau ou d'une liste (ArrayAdpater)
– d'un curseur SQLite (CursorAdaptor)
– d'une collection personnalisable(SimpleCursorAdapter)
● l'adaptateur permet un accès aux données et est responsable de l'affichage de chaque élément de la collection– fournit un objet de type View
antislashn.org Android - Autres composants graphiques 9- 17/33
Spinner
● Il est possible de personnaliser la vue d'affichage en configurant l'adaptateur● méthode setDropDownViewResource(...)● Android fournit une vue prédéfinie
– android.R.layout.simple_spinner_item
● La réaction au changement de sélection passe par l'utilisation d'un écouteur du type AdapterView.OnItemSelectedListener
antislashn.org Android - Autres composants graphiques 9- 18/33
Spinner
● Exemple utilisant un ArrayAdapter et des ressources
<resources> <string name="hello">Hello World, Spinner01Activity!</string> <string name="app_name">Spinner01</string> <string name="spinner_prompt">Faites un choix</string> <string-array name="civilites"> <item >M</item> <item >Mme</item> <item >Mlle</item> </string-array></resources>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Civilité : " /> <Spinner android:id="@+id/spinner1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:prompt="@string/spinner_prompt" /></LinearLayout>
antislashn.org Android - Autres composants graphiques 9- 19/33
Spinner
● Exemple utilisant un ArrayAdapter et des ressources
public class Spinner01Activity extends Activity {
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);Spinner spinner = (Spinner) findViewById(R.id.spinner1);ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.civilites,android.R.layout.simple_spinner_item );
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);spinner.setAdapter(adapter);spinner.setOnItemSelectedListener(new SpinnerListener());
}public class SpinnerListener implements OnItemSelectedListener{
@Overridepublic void onItemSelected(AdapterView<?> parent, View v, int pos, long id) {
Toast.makeText(parent.getContext(),parent.getItemAtPosition(pos).toString() , Toast.LENGTH_SHORT).show();}@Overridepublic void onNothingSelected(AdapterView<?> adapter) { }
}}
antislashn.org Android - Autres composants graphiques 9- 20/33
Spinner
● Exemple utilisant un ArrayAdapter● extrait de code
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);Spinner spinner = (Spinner) findViewById(R.id.spinner1);List<String> items = new ArrayList<String>();items.add("M");items.add("Mme");ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, items);adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
items.add("Mlle");}
antislashn.org Android - Autres composants graphiques 9- 21/33
ProgressBar
● Permet de visualiser un progression● par défaut un indicateur tournant
<ProgressBar android:id="@+id/progressBar1" style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:layout_marginTop="20dp" />
<ProgressBar android:id="@+id/progressBar2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/progressBar1" android:layout_marginLeft="100dp" android:layout_marginTop="38dp" />
antislashn.org Android - Autres composants graphiques 9- 22/33
ProgressBar
● Code de progression (extrait)● dans méthode onCreate()...new Thread(new Runnable() {
public void run() {while (mProgressStatus < 100) {
mProgressStatus++;try {
Thread.sleep(50);} catch (InterruptedException e) {
e.printStackTrace();}mHandler.post(new Runnable() {
public void run() {barHorizontal.setProgress(mProgressStatus);
}});
}}
}).start();...
mHandler est de type Handler
antislashn.org Android - Autres composants graphiques 9- 23/33
ProgressBar
● Le Handler appartient au thread principal● thread de l'activité
● Le thread secondaire doit signaler à l'activité de mettre à jour la barre de progression● le thread secondaire est celui qui compte jusqu'à 100
● Nous utilisons ici une message, le Handler, qui est un Runnable
Thread de comptage Thread de 'IHM
post() HandlerRunnable
Activity
antislashn.org Android - Autres composants graphiques 9- 24/33
TimePicker et DatePicker● Widgets facilitant la saisie des dates et heures
antislashn.org Android - Autres composants graphiques 9- 25/33
TimePicker et DatePicker● La réaction à la saisie est réalisée par des listeners
● OnTimeChangedListener● OnTimeChangedListener
● Par défaut le format de TimePicker est sur 12 heures● utiliser setIs24HourView(true) pour passer à un
format 24 heures
antislashn.org Android - Autres composants graphiques 9- 26/33
TimePicker et DatePicker● L'enregistrement du listener du TimePicker se
fait classiquement
– this est l'activité qui implémente OnTimeChangedListener
● L'enregistrement du listener du DatePicker est effectué par une méthode d'initialisation● qui prend comme premiers paramètres :
– l'année– le mois – 1– le jour dans le mois
– this est l'activité qui implémente OnDateChangedListener
timePicker.setOnTimeChangedListener(this);
datePicker.init(2012, 7, 23, this);
antislashn.org Android - Autres composants graphiques 9- 27/33
Chronometer
● Widget affichant un chronomètre● décompte par seconde● on peut lui fournir une base de décompte
– l'heure courante par défaut– méthode setBase(long)
● ne maintient pas la valeur du décompte, uniquement la base– récupération par la méthode getBase()
● le format d'affichage est sous la forme MM:SS, puis H:MM:SS lorsque 60 minutes sont dépassées– le format peut-être personnalisé avec un message
● méthode setFormat(String) ou attribut android:format
antislashn.org Android - Autres composants graphiques 9- 28/33
Chronometer
...
<Chronometer android:id="@+id/chronometer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/resetButton" android:layout_alignBottom="@+id/resetButton" android:layout_toRightOf="@+id/resetButton" android:text="Chronometer" />...
...chronometer = (Chronometer) findViewById(R.id.chronometer);
chronometer.setFormat("VALEUR : %s");chronometer.setBase(SystemClock.elapsedRealtime());chronometer.setOnChronometerTickListener(this);...
%s sera remplacépar MM:SS ou H:MM:SSen fonction du comptage
antislashn.org Android - Autres composants graphiques 9- 29/33
Chronometer
● Il est possible de réagir à chaque comptage en implémentant un listener● OnChronometerTickListener● on peut alors faire un calcul entre la base de comptage
et une autre valeur– heure courante, durée depuis le boot
public void onChronometerTick(Chronometer chronometer) {Log.d(this.getClass().getCanonicalName(),">>>> "+
(SystemClock.elapsedRealtime()-chronometer.getBase()));}
antislashn.org Android - Autres composants graphiques 9- 30/33
Chronometer
● Avant 59:59
● Après ...
antislashn.org Android - Autres composants graphiques 9- 31/33
AnalogClock et Digitallock
● Fait juste ce que ça doit faire : afficher l'heure● sous forme digitale ou analogique
...<AnalogClock android:id="@+id/analogClock1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" />
<DigitalClock android:id="@+id/digitalClock1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/analogClock1" android:layout_centerHorizontal="true" android:layout_marginTop="47dp" android:text="DigitalClock" />...
antislashn.org Android - Autres composants graphiques 9- 32/33
ImageView
● Permet d'afficher une image<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" >
<ImageView android:id="@+id/imageView1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:src="@drawable/canada_1"
android:layout_gravity="center" /></LinearLayout>
antislashn.org Android - Autres composants graphiques 9- 33/33
Autres widgets● De nombreux autres widgets existent
● le nombre de widgets disponibles augmente avec les nouvelles versions
● CheckedTextView utilisé avec les ListView● RatingBar qui permet de donner une note sous forme d'un
ration de 1 à 5 étoiles● gestion multimédia : MediaController, Gallery, VideoView
● Nouveautés de l'API 11● CalendarView : vue calendrier● ListPopupWindow : liste de choix dans une popup
● Une bonne approche est de voir ce qui est disponible comme widget dans ADT, et de lire la documentation
antislashn.org Android - Les menus 10 - 2/13
Les menus● Android supporte deux types de menu
● les menus d'activité● les menus contextuels
● La construction des menus peut être effectuée● dynamiquement par programmation● par déclaration dans un fichier XML
– méthode à privilégier
antislashn.org Android - Les menus 10 - 3/13
Les menus
● La déclaration des menus est effectuée dans une fichier XML situé dans res/menu
● La syntaxe est simple● la racine menu accepte des balise
– item pour un élément de menu– menu pour déclarer un sous-menu
● deux niveaux maximum
● principaux attributs de la balise item– title : titre de l'élément de menu
– icon : icône de l'élément de menu
– onClick : méthode de l'activité à invoquer (depuis Android 3)
– checked : présélection de l'élément du menu
antislashn.org Android - Les menus 10 - 4/13
Les menus
● Exemple de déclaration de menu<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu1" android:title="Menu 1">
</item> <item android:id="@+id/menu2" android:title="Menu 2"> <menu> <item android:id="@+id/item1" android:title="Item 1"/> <item android:id="@+id/item2" android:title="Item 2"/> </menu> </item> </menu>
antislashn.org Android - Les menus 10 - 5/13
Les menus
● La balise group permet de regrouper les éléments d'un menu afin :● de leur attribuer les mêmes propriétés● d'ajouter des cases à cocher, boutons radio aux
éléments du menu
antislashn.org Android - Les menus 10 - 6/13
Les menus
● Utilisation des menus● les menus ont été déclarés dans le fichier XML● il est nécessaire de transformer ce XML en instance de
Menu– utilisation de la méthode getMenuInflater de la classe Activity
Menu menu = new Menu();MenuInflater inflater = getMenuInflater();inflater.inflate(R.menu.menu, menu);
antislashn.org Android - Les menus 10 - 7/13
Les menus
● Menu d'activité● le menu d'activité est activé lorsque l'utilisateur appui
sur la touche Menu– depuis Android 3 les options de menus sont regroupés par
défaut dans le sous-menu de la barre d'action● création
– le menu est créé dans la méthode onCreateOptionsMenu de l'activité
● doit retourner true pour permettre l'affichage du menu
public boolean onCreateOptionsMenu(Menu menu) {MenuInflater inflater = getMenuInflater();inflater.inflate(R.menu.menu, menu);return true;
}
antislashn.org Android - Les menus 10 - 8/13
Les menus
● Menu d'activité● utilisation du menu
– pour les version > Android 3.0 l'attribut onClick de la balise item permet l'appel d'une méthode de l'activité
– pour toutes les version : implémenter la méthode onOptionsItemSelected de l'activité (ou le fragment)
● retourne true si l'action est traitée, false dans le cas contraire
public boolean onOptionsItemSelected(MenuItem item) {Toast.makeText(this, item.getTitle() + " [" + item.getItemId() + "]",
Toast.LENGTH_SHORT).show();return super.onOptionsItemSelected(item);
}
appel de la méthode de la classe mère pourgérer les options supplémentaires des menus partagés
antislashn.org Android - Les menus 10 - 9/13
Les menus
● Menu d'activité● si le menu doit être modifié dynamiquement après sa
création il faut utiliser la méthode onPrepareOptionsMenu– depuis Android 3.0 il faut aussi appeler la méthode invalidateOptionsMenu
antislashn.org Android - Les menus 10 - 10/13
Les menus
● Menu contextuel● un menu contextuel apparaît si l'utilisateur effectue un
appui long sur l'écran– il faut donc que l'appui long soit géré par le widget possédant
le menu contextuel– méthode registerForContextMenu
● appeler cette méthode après setContentView, lorsque la vue est construite
● la méthode reçoit l'identifiant du widget sur lequel ajouter le menu contextuel
● la création du menu est effectuée dans la méthode onCreateContextMenu
● la méthode onContextItemSelected est utilisée pour traiter le choix de l'utilisateur
antislashn.org Android - Les menus 10 - 11/13
Les menus
● Exemple d'utilisation d'un menu contextuelpublic class MenuContextuelActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); View v = findViewById(R.id.layout); registerForContextMenu(v); } public void onCreateContextMenu(ContextMenu menu,View v,
ContextMenu.ContextMenuInfo infos){ super.onCreateContextMenu(menu, v, infos); switch (v.getId()) {
case R.id.layout:MenuInflater inflater = getMenuInflater();inflater.inflate(R.menu.menuctx, menu);break;
} } public boolean onContextItemSelected(MenuItem item){ Toast.makeText(this, item.getTitle()+" ["+item.getItemId()+"]",
Toast.LENGTH_SHORT).show(); return super.onContextItemSelected(item); }}
menu contextuel sur tout le layout
choix du menu contextuel à afficher
antislashn.org Android - Les menus 10 - 12/13
Les menus
● Menu contextuel sur une ListView● le menu contextuel est associé à la ListView● il sera affiché pour chaque item de la liste● il faut en général récupérer l'item sur lequel est affiché
le menu contextuel● Lors de l'ajout du menu à la vue, celle-ci peut
ajouter des informations aux items du menu.● la méthode getMenuInfo() de la classe MenuItem
retourne ces informations● dans le cas d'une ListView, les informations sont
retournées en tant qu'instance de type AdapterView.AdapterContextMenuInfo
antislashn.org Android - Les menus 10 - 13/13
Les menus
● Menu contextuel sur une ListView● exemple de code (extrait)
@Overridepublic boolean onContextItemSelected(MenuItem item){
AdapterView.AdapterContextMenuInfo info =(AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
String text = items.get(info.position);Toast.makeText(this, text, Toast.LENGTH_SHORT).show();return super.onContextItemSelected(item);
}
items est la liste des items de l'adaptateur
antislashn.org Android - Les notifications à l'utilisateur 11 - 1/21
Les notificationsà l’utilisateur
antislashn.org Android - Les notifications à l'utilisateur 11 - 2/21
Notifications
● Les notifications avertissent l'utilisateur● Android propose trois types de notification
● le toast : notification rapide sur l'écran● la boite de dialogue : permet une interaction avec
l'utilisateur● la barre de notifications : permet une notification par
des tâches de fond sans perturber l'utilisateur– les notifications sont ajoutées les unes aux autres
antislashn.org Android - Les notifications à l'utilisateur 11 - 3/21
Toast● Message apparaissant durant quelques secondes
● ne possède aucun bouton, l'utilisateur ne peut que lire le message● le message s'affiche en premier plan
● méthodes utiles de la classe Toast● public static Toast makeText(Context ctx,T t, int duration)
– ctx est le contexte graphique
– t peut être de type int ou CharSequence, pour identifiant de ressource ou un message
● show()– affiche le message
● d'autres méthodes permettent de changer le layout par défaut d'un toast
Toast.makeText(this, "Bonjour", Toast.LENGTH_SHORT).show();
antislashn.org Android - Les notifications à l'utilisateur 11 - 4/21
Les boites de dialogue● Fenêtre modale qui possède des boutons pour interagir
avec l'utilisateur● Les boites de dialogues héritent de la classe Dialog● Android fournit des boites de dialogues pour les besoins
les plus courants● AlertDialog : alerte● DatePickerDialog : choix d'une date● TimePickerDialog : choix d'une heure● ProgessDialog : information sur un traitement en cours● CharacterPickerDialog : choix d'un caractère accentué
antislashn.org Android - Les notifications à l'utilisateur 11 - 5/21
AlertDialog
● La classe interne Builder permet de simplifier la création de la boite de dialogue
● De nombreuses méthode permettent d'ajouter une message, titre, liste d'items, etc.
● Les transparents suivants présentent des exemples de créations et utilisation de boites d'alerte● alerte avec un message● alerte avec une liste de choix
● L'affichage de la boite de dialogue est effectué avec sa méthode show()
● La boite de dialogue est fermée automatiquement ● cf. les méthodes dismiss() et cancel()
antislashn.org Android - Les notifications à l'utilisateur 11 - 6/21
AlertDialog
● Les exemples suivants montrent comment créer et utiliser différentes boites de dialogues
● L'activité principale contient tout le code● extrait du code
public class AlertDialogActivity extends Activity implements OnClickListener {
private AlertDialog simpleAlert;private AlertDialog choiceAlert;final CharSequence langages[] = {"C/C++","Java","Python","PHP"};
@Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); simpleAlertBuilder(); choiceAlertBuilder(); }...
méthode de construction desboîtes de dialoguecode détaillé plus loin
antislashn.org Android - Les notifications à l'utilisateur 11 - 7/21
Alerte avec message
● L'objectif est de coder la création et le comportement d'une boite d'alerte simple
● Création de la boite● la méthode est dans l'activité● simpleAlert est une propriété de l'activité
private void simpleAlertBuilder(){AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setMessage("Voulez vous quitter cette application ?");builder.setPositiveButton("Oui", this).setNegativeButton("Non", this);simpleAlert = builder.create();
}mise en place du listener
antislashn.org Android - Les notifications à l'utilisateur 11 - 8/21
AlertDialog personnalisée
● L'alerte personnalisée va permettre d'afficher un TextView
antislashn.org Android - Les notifications à l'utilisateur 11 - 9/21
AlertDialog personnalisée
● Le layout de base est décrit dans le fichier custom_alert.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="15dip"> <TextView android:id="@+id/TextView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Entrer quelque chose ci-dessous :" android:paddingBottom="10dip" /> <EditText android:id="@+id/EditText1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/TextView1" /> </RelativeLayout>
antislashn.org Android - Les notifications à l'utilisateur 11 - 10/21
AlertDialog personnalisée
● Dans le code de création du AlertDialog il faut ajouter le layout créé
LayoutInflater inflater = LayoutInflater.from(this);final View customView = inflater.inflate(R.layout.custom_alert, null); AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setView(customView);builder.setTitle("Modifiez la valeur");builder.setIcon(android.R.drawable.ic_dialog_alert);builder.setPositiveButton("OK", new OnClickListener() {
@Overridepublic void onClick(DialogInterface dialog, int which) {
TextView tv = (TextView) customView.findViewById(R.id.EditText1);Toast.makeText(AlertDialogPersonnaliseeActivity.this, tv.getText(), Toast.LENGTH_SHORT).show();
}});builder.setNegativeButton("Cancel", new OnClickListener() {
@Overridepublic void onClick(DialogInterface dialog, int which) {
Toast.makeText(AlertDialogPersonnaliseeActivity.this, "CANCEL", Toast.LENGTH_SHORT).show();}
});builder.show();
création du layout à partir du XML
ajout du layout à l'AlertDialog
ajout du bouton OK et de son listener
ajout du bouton Cancel et de son listener
affichage de la boite de dialogue
antislashn.org Android - Les notifications à l'utilisateur 11 - 11/21
Alerte avec message
● L'activité hérite de l'interface DialogInterface.OnClickListener● le traitement des clics sur les boutons de la boite de
dialogue est effectuée par la méthode onClick
public void onClick(DialogInterface dialog, int which) {if(dialog==simpleAlert){
switch(which){case DialogInterface.BUTTON_POSITIVE:
Toast.makeText(this, "Fermeture application", Toast.LENGTH_SHORT).show();//this.finish();
break;case DialogInterface.BUTTON_NEGATIVE:
Toast.makeText(this, "On continue !!!", Toast.LENGTH_SHORT).show();simpleAlert.cancel();
}}
}
quelle boite est affichée ?
fermeture de la boite
antislashn.org Android - Les notifications à l'utilisateur 11 - 12/21
Alerte avec choix
● L'objectif est de créer un boite avec une liste de choix
antislashn.org Android - Les notifications à l'utilisateur 11 - 13/21
Alerte avec choix
● Création de la boite
● Comportement lors du clic de l'utilisateur
private void choiceAlertBuilder(){AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("Choix du langage");builder.setItems(langages, this);choiceAlert = builder.create();
}
public void onClick(DialogInterface dialog, int which) {if(dialog==simpleAlert){
...}if(dialog==choiceAlert){
Toast.makeText(this, langages[which], Toast.LENGTH_SHORT).show();}
}
antislashn.org Android - Les notifications à l'utilisateur 11 - 14/21
AlertDialog
● Les listes de choix peuvent aussi contenir des boutons radios ou des cases à cocher● cf. les méthodes setSingleChoiceItems et setMultiChoiceItems du builder
● Il est préférables d'utiliser les méthodes de DialogFragment pour pour gérer les boites de dialogue● gestion de l'état si l'application est mise en pause● les exemples présentés ne suivent pas ce modèle pour
avoir un code plus concis
antislashn.org Android - Les notifications à l'utilisateur 11 - 15/21
Barre de notification
● La barre de notification permet l'affichage de notifications qui sont empilées par le système, sans perturber l'utilisateur● depuis Android 3.0 les notifications sont affichées par la
barre d'état (en bas de l'écran)
antislashn.org Android - Les notifications à l'utilisateur 11 - 16/21
Barre de notification● La gestion d'une notification est très simple
● création de la notification– on précise
● le titre de la notification● le texte de la notification● l'information associée à la notification● l'icône affichée dans la barre (setSmallIcon)● une image dans la notification (setLargeIcon)
– une intention peut être ajoutée pour que l'utilisateur puisse réagir à la notification (setIntent)
– la création est différente depuis Android 3.0 (API 11)● utilisation d'un Notification.Builder
● envoi de la notification– elle s'affiche alors dans la barre de notification (ou d'état)
antislashn.org Android - Les notifications à l'utilisateur 11 - 17/21
Notification
● Exemple de création de notification jusqu'à l'API 11
...Notification notification = new Notification(R.drawable.bluetooth_notification,
"Texte notification : "+ numeroNotification,System.currentTimeMillis());
String tag = this.getString(R.string.app_name);Intent intent = new Intent(this, ReactionANotificationActivity.class);PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);notification.setLatestEventInfo(this, "Titre notification",
"Explication de la notification", pIntent);notification.flags = Notification.FLAG_SHOW_LIGHTS;...
antislashn.org Android - Les notifications à l'utilisateur 11 - 18/21
Notification
● Exemple de création de notification à partir de l'API 11
antislashn.org Android - Les notifications à l'utilisateur 11 - 19/21
Notification
● Envoi de la notification● l'envoi utilise le service d'envoi des notification: NotificationManager– est récupéré par l'appel à getSystemService(NOTIFICATION_SERVICE)
● la notification est envoyé via la méthode notify(...)● public void notifiy(int id,
Notification notification)● public void notifiy(String tag, int id,
Notification notification)– id : identifiant de la notification
– tag : tag de la notification
– notification : instance de Notification à envoyer
antislashn.org Android - Les notifications à l'utilisateur 11 - 20/21
Notification
● Envoi de la notification● tag et id forment un identifiant unique● si tag n'est pas préciser ou null, seul id est utilisé● l'identifiant est unique pour l'application● si l'identifiant n'évolue pas entre deux notifications, la
notification déjà envoyée est mise à jour● si l'identifiant évolue d'un envoie à l'autre les
notifications s'ajoutent
antislashn.org Android - Les notifications à l'utilisateur 11 - 21/21
Notification
● Exemple de code d'envoi d'une notification
...NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);if (numeroNotification > 0)
manager.cancel(tag, numeroNotification);manager.notify(tag, ++numeroNotification, notification);...
antislashn.org Android - La persistance des données 12 - 2/36
Persistance de données
● La persistance des données peut être effectuée● par des fichiers de préférence
– sauvegarde des types primitifs dans des fichiers XML– framework fournit par Android
● par la lecture/écriture directe sur le système de fichiers– sauvegarde d'images, ...– Android présente une API pour la gestion des fichiers
temporaires, copie du stockage interne vers la carte SD, etc.● par persistance en base de données
– base de données SQLite
antislashn.org Android - La persistance des données 12 - 3/36
Préférences utilisateur
● Android fournit un framework pour gérer les préférences utilisateur● les préférences sont de type primitif et String● sauvegarde sous forme de clé / valeur● les fichiers de préférences sont au format XML
● Fichier de préférences● par défaut un fichier de préférence est créé par
application– nom complètement qualifié de l'application
● SharedPreference permet la gestion du fichier
antislashn.org Android - La persistance des données 12 - 4/36
Préférences utilisateur
● Utiliser le fichier des préférences● récupérer une instance de SharedPreferences via la
méthode getPreferences(...) de l'activité
– modes d'ouverture● MODE_PRIVATE : uniquement l'application● MODE_WORLD_READABLE : lecture par les autres applications● MODE_WORLD_WRITEABLE : écriture par les autres application
● Pour utiliser un autre fichier que celui par défaut, il faut utiliser la méthode getSharedPreferences(...) qui prend comme– premier paramètre : le nom du fichier– second paramètre : le mode d'ouverture
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
antislashn.org Android - La persistance des données 12 - 5/36
Préférences utilisateur
● Écriture des préférences● utiliser la classe SharedPreferences.Editor
– un éditeur est récupéré par la méthode edit()
● puis utiliser une série de méthodeputXxx(String key, T value) pour mettre à jour les paires clé/valeur– où Xxx vaut Boolean, String, Int, Long, Float, …
– et T est de type Boolean, String, Int, Long, Float, …
● et écrire les données par un commit()– sinon rien ne sera sauvegardé
antislashn.org Android - La persistance des données 12 - 6/36
Préférences utilisateur
● Exemple d'écriture de préférences● la paire clé/valeur est lue dans un formulaire● l'écriture est déclenchée par un bouton
public void enregistrerPreference(View v){EditText key = (EditText) findViewById(R.id.key);EditText value = (EditText) findViewById(R.id.value);SharedPreferences prefs = getPreferences(MODE_PRIVATE);
Editor editor = prefs.edit(); editor.putString(key.getText().toString(),value.getText().toString());editor.commit();
}
antislashn.org Android - La persistance des données 12 - 7/36
Préférences utilisateur
● Lecture des préférences● la lecture est effectuée sur un objet de type SharedPreference
● une série de méthodes permet de lire les valeurs :public T getXxx(String key, T defValue) – T type retourné par la méthode– Xxx vaut Boolean, String, Int, Long, Float, …
– defValue est la valeur par défaut● lecture de toutes les paires clé/valeur par
– public Map<String ?> getAll()
● vérification de l'existence d'une entrée– public boolean contains(String key)
antislashn.org Android - La persistance des données 12 - 8/36
Préférences utilisateur
● Exemple de lecture de toutes les préférences● déclenchement par un bouton● écriture dans les logs
public void lirePreferences(View v){SharedPreferences prefs = getPreferences(MODE_PRIVATE);Map<String, ?> valeurs = prefs.getAll();for(String k : valeurs.keySet())
Log.i("PreferencesActivity", k+" : "+prefs.getString(k, ""));}
antislashn.org Android - La persistance des données 12 - 9/36
Préférences utilisateur
● Partage de préférences● côté fournisseur de préférences●
●
●
●
● côté consommateur de préférences
public void enregistrerPreference(View v) {EditText key = (EditText) findViewById(R.id.key);EditText value = (EditText) findViewById(R.id.value);SharedPreferences prefs = getSharedPreferences("CustomPref", MODE_WORLD_READABLE);Editor editor = prefs.edit();editor.putString(key.getText().toString(), value.getText().toString());editor.commit();
}
myContext = createPackageContext("org.antislashn.android.preferences", 0);SharedPreferences sharedPref = myContext.getSharedPreferences("CustomPref",
Context.MODE_WORLD_READABLE); for (Entry<String, ?> pair : sharedPref.getAll().entrySet()) {
addPreference(pair.getKey(), pair.getValue());}
antislashn.org Android - La persistance des données 12 - 10/36
Système de fichiers
● Les fichiers permettent de sauvegarder des données plus complexes que des types de base● son, image, …
● Les fichiers peuvent être créés sur le stockage interne ou externe (carte SD)● par défaut sur le stockage interne● l'accès au fichier interne est restreint à l'application
– l'utilisateur et les applications ne peuvent pas y accéder
● Prise en charge de la gestion des fichiers temporaires
antislashn.org Android - La persistance des données 12 - 11/36
Système de fichiers – stockage interne
● Écriture dans le fichier● Ouverture du flux fichier
– méthode de la classe Context :– public FileOutputStream onpenFileOutput(String name,
int mode)
● Écriture dans le flux retourné par la méthode– méthodes write(...)
● Fermeture du flux– méthode close()
● L'ensemble de ces méthodes est susceptible de lever des exceptions
antislashn.org Android - La persistance des données 12 - 12/36
Système de fichiers – stockage interne● Lecture depuis le fichier
● Ouverture du flux fichier– méthode de la classe Context :– public FileInputStream onpenFileInput(String name)
● Lecture depuis le flux retourné par la méthode– méthodes read(...)
● Fermeture du flux– méthode close()
● L'ensemble de ces méthodes est successible de lever des exceptions
● Suppression d'un fichier● méthode de Context
– public boolean deleteFile(String name)
antislashn.org Android - La persistance des données 12 - 13/36
Système de fichiers – stockage interne
● Exemple de lecture - écriturepublic void ecrireFichier(View v){
byte[] datas = {1,2,3,4,5,6,7,8,9,10};try {
FileOutputStream out = this.openFileOutput("fichierInterne.dat", MODE_APPEND);out.write(datas);out.close();
} catch (Exception e) {Log.e("FichierInterneActivity","Erreur sur fichier",e);
}}
public void lireFichier(View v){try {
FileInputStream in = this.openFileInput("fichierInterne.dat");int b;do{
b=in.read();Log.i("FichierInterneActivity","Octet lu : "+b);
}while(b!=-1);in.close();
} catch (Exception e) {Log.e("FichierInterneActivity","Erreur sur fichier",e);
}}
antislashn.org Android - La persistance des données 12 - 14/36
Système de fichier – stockage sur SD
● Les fichiers stockés sur la carte SD sont publics● l'utilisateur et les autres applications peuvent y accéder● le stockage externe peut aussi être interne à l'appareil
– carte SD intégrée● le stockage externe peut être un support amovible
– l'utilisateur peut retirer à tout moment la carte– l'application doit tenir compte de l'absence de support
● Il faut interroger l'environnement pour connaître la disponibilité de la carte SD● méthode de la classe Environment● public static String getExternalStorageState()
– renvoie l'état sous forme de String
antislashn.org Android - La persistance des données 12 - 15/36
Système de fichiers – stockage sur SD
● Constantes de la classe Environment représentant l'état du support
Etat Description
MEDIA_BAD_REMOVAL média retiré sans avoir été correctement démonté
MEDIA_CHECKING média en cours de vérification
MEDIA_MOUNTED média correctement monté en lecture/écriture
MEDIA_MOUNTED_READ_ONLY média correctement monté en lecture seule
MEDIA_NOFS média présent, mais système de fichiers non supporté
MEDIA_REMOVED média absent
MEDIA_SHARED média présent, non monté et partagé en tant périphérique USB
MEDIA_UNMOUNTABLE média présent, mais ne peut pas être monté
MEDIA_UNMOUNTED média présent mais non monté
antislashn.org Android - La persistance des données 12 - 16/36
Système de fichiers – stockage sur SD
● Un répertoire est affecté à chaque application● les fichiers de données sont répartis dans des sous-
répertoires : Music, Alarms, ….– correspond à des constantes de la classe Environment
Répertoire Contante Contenu
Music/ DIRECTORY_MUSIC fichiers de musique
Podcasts/ DIRECTORY_PODCASTS podcasts
Ringtones/ DIRECTORY_RINGTONES sonneries
Alarms/ DIRECTORY_ALARMS sons des alarmes
Notifications/ DIRECTORY_NOTIFICATIONS sons des notifications
Pictures/ DIRECTORY_PICTURES photos
Movies/ DIRECTORY_MOVIES films
Downloads/ DIRECTORY_DOWNLOADS autres types de fichiers
antislashn.org Android - La persistance des données 12 - 17/36
Système de fichiers -stockage sur SD
● La méthode getExternalFilesDir retourne un objet de type File représentant le sous-répertoire de données
● Toutes les opérations d'écriture sur la carte SD nécessite une permission d'écriture● dans le fichier AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
antislashn.org Android - La persistance des données 12 - 18/36
Système de fichiers – stockage sur SD
● Les fichiers communs à plusieurs applications sont mis dans une arborescence spécifique● les fichiers créés dans cette arborescences ne sont pas
supprimés même si l'application qui les a créés est désinstallée
● même organisation d'arborescence en fonction du type de données
● objet de type File représentant le sous-répertoire de données est retourné par la méthode : getExternalStoragePublicDirectory
antislashn.org Android - La persistance des données 12 - 19/36
Système de fichiers – stockage sur SD
● Exemple d'écriture sur SD
public void ecrireFichierExterne(View v){byte[] datas = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };String state = Environment.getExternalStorageState();if(!state.equals(Environment.MEDIA_MOUNTED)){
Log.e("FichierExterneActivity", "La carte SD n'est pas montée en écriture");Toast.makeText(this, "La carte SD n'est pas montée en écriture", Toast.LENGTH_SHORT).show();
return;}try {
File dir = this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);File file = new File(dir,"test.data");file.createNewFile();FileOutputStream fout = new FileOutputStream(file);fout.write(datas);fout.close();Toast.makeText(this, "Ecriture effectuée", Toast.LENGTH_SHORT).show();
} catch (Exception e) {Log.e("FichierInterneActivity", "Erreur sur fichier", e);
}}
antislashn.org Android - La persistance des données 12 - 20/36
Système de fichiers – stockage sur SD
● Exemple de lecture depuis la SD
public void lireFichierExterne(View v){String state = Environment.getExternalStorageState();if(!(state.equals(Environment.MEDIA_MOUNTED_READ_ONLY) || state.equals(Environment.MEDIA_MOUNTED))){
Log.e("FichierExterneActivity", "La carte SD n'est pas montée");Toast.makeText(this, "LLa carte SD n'est pas montée", Toast.LENGTH_SHORT).show();
return;}try{
File dir = this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);File file = new File(dir,"test.data");FileInputStream fin = new FileInputStream(file);int b;do {
b = fin.read();Log.i("FichierExterneActivity", "Octet lu : " + b);
} while (b != -1);fin.close();Toast.makeText(this, "Lecture effectuée", Toast.LENGTH_SHORT).show();
}catch(Exception e){Log.e("FichierInterneActivity", "Erreur sur fichier", e);
}}
antislashn.org Android - La persistance des données 12 - 21/36
Système de fichier - fichier temporaire
● Un emplacement spécifique à chaque application est réservé pour les fichiers temporaires● en interne pour des fichiers de petite taille
– public File getCacheDir() de la classe Context
● sur le support SD pour des fichiers de grande taille– public File getExternalCacheDir() de la classe Context
● l'application est chargée de supprimer le fichier temporaire– doit être supprimé dès que l'application n'en a plus besoin
● les fichiers temporaires sont supprimés si l'application est désinstallée
antislashn.org Android - La persistance des données 12 - 22/36
SQLite● Une application peut stocker des données dans une ou
plusieurs bases de données SQLite● site officiel : http://www.sqlite.org/● les bases de données sont privées à l'application qui les a
créées– passer par un fournisseur de contenu pour les rendre publiques
● Android ne dispose pas de framework ORM● Object Relational Mapping● il faut programmer l'exécution des requêtes SQL
● L'application doit tenir compte● de la création de la base● de sa mise à jour
antislashn.org Android - La persistance des données 12 - 23/36
SQLite
● Classes de stockage● INTEGER : nombres entiers, signés ou non
– utilisé pour les clés primaire● PRIMARY KEY AUTOINCREMENT
● REAL : nombres réels● TEXT : données textuelles● BLOB : stockage de données sous leur forme binaire● NULL : si la donnée est nulle
antislashn.org Android - La persistance des données 12 - 24/36
SQLite
● SQlite et Android● les données brutes (images, fichiers, …) ne sont
généralement pas enregistrées dans les tables (BLOB)– les noms de fichiers, chemin sont enregistrés dans la base
● il est préférable d'ajouter aux tables un index auto-incrémenté– nommé _id
– la table pourra ainsi être utilisée par un ContentProvider
antislashn.org Android - La persistance des données 12 - 25/36
SQLite
● Afin de gérer le cycle de vie de la base, Android fournit une classe abstraite SQLiteOpenHelper● le développeur doit créer une classe qui la spécialise● il faut redéfinir des méthodes callback du cycle de vie
– une méthode de création public void SQLiteDatabase onCreate(SQLiteDatabase db)où db est la base de donnée manipulée
– une méthode de mise à jour public void SQLiteDatabase onUpdate(SQLiteDatabase db,
int odlVersion, int newVersion)où db est la base de donnée manipulée
oldVersion est la version précédente de la basenewVersion la nouvelle version de la base
antislashn.org Android - La persistance des données 12 - 26/36
SQLite
● Exemple de code pour le helper
public class ApplicationHelper extends SQLiteOpenHelper {private static final int version = 1;private static final String bdName = "todoBD";
public ApplicationHelper(Context context) {super(context, bdName, null, version);
}
@Overridepublic void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE todo ( kp INTEGER PRIMARY KEY AUTOINCREMENT, item VARCHAR(100);";db.execSQL(sql);
}
@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub}
}
antislashn.org Android - La persistance des données 12 - 27/36
SQLite
● La classe SQLiteOpenHelper fournit la méthode● public synchronized SQLiteDatabase getWritableDatabase()
● permet de gérer la base via la classe SQLiteDatabase● lors du premier appel de cette méthode, la base de
données est réellement créée– les méthodes suivantes seront successivement invoquées
● onCreate● onUpdate● onOpen
● pour avoir une base de données en lecture seule il faut appeler getReadableDatabase– getWriteableDatabase peut aussi retourner une base en
lecture seule s'il y un problème (disque plein par exemple)
antislashn.org Android - La persistance des données 12 - 28/36
SQLite
● La classe SQLiteDatabase possède les méthodes d'interrogation et gestion de la base● les plus utiles
– public void execSql(String sql)● permet l'exécution de requêtes ne renvoyant pas de résultat
– sélection d'enregistrements : méthodes query(...) ● renvoie une instance de type Cursor
– insertion d'enregistrements : méthodes insert(...)● renvoie le nombre d'enregistrements insérés
– mise à jour d'enregistrements : méthodes update(...)● renvoie le nombre d'enregistrements mis à jour
– suppression d'enregistrements : méthodes delete(...)● renvoie le nombre d'enregistrements supprimés
antislashn.org Android - La persistance des données 12 - 29/36
SQLite● Interrogation de la base
● utilisation de la classe SQLiteDatabase● les requêtes retournent un Cursor● la méthode query accepte les paramètres suivants
– distinct : booléen facultatif indiquant que le résultat doit contenir des valeurs uniques
– table : nom de la table
– projection : tableau de String contenant les colonnes
– selection : clause WHERE, peut inclure des paramètres (?)
– selectionArgs : tableau des paramètre de la clause WHERE
– groupBy : clause GROUP BY
– having : clause HAVING
– orderBy : clause ORDER BY
– limit : clause LIMIT
antislashn.org Android - La persistance des données 12 - 30/36
SQLite
● Support des transactions● cf. la documentation de la classe SQLiteDatabase
● La classe Cursor gère le curseur résultat d'une sélection● récupération des valeurs de champ par des méthodesT getT(int columnIndex)où T est le type à récupérer : getString, getInt, …
● déplacements avec les méthodes de type move(...)– moveToFirst(), move(int offset), moveToNext(), …
● la première colonne résultat est numéroté 0● et bien d'autres
– cf. la documentation de la classe Cursor
antislashn.org Android - La persistance des données 12 - 31/36
SQLite
● L'outil adb permet d'ouvrir un client SQLite● situé dans le répertoire plateform-tools du SDK● les commandes du client commencent par le caractère
point (.)– databases : liste les bases de données
– help : affiche aide
– exit : sort de l'application SQLite
● cf. la documentation du client SQLite3– lien : www.sqlite.org/sqlite.html
$ adb -s emulator-5554 shell# sqlite3 /data/data/package.appli/databases/maBase.dbsqlite>.databases
antislashn.org Android - La persistance des données 12 - 32/36
SQLite - exemple
● Nous allons étudier un exemple complet d'une application utilisant une base de données● création de la base de données à la première utilisation
de l'application● interrogation de la base de données
● L'application permet de récupérer une ville et ses coordonnées géographique par son code postal● les données livrées avec l'application sous forme d'un
fichier assets/villes.csv– voir le projet Eclipse "France"
antislashn.org Android - La persistance des données 12 - 33/36
SQLite – exemple
● Structure de la base de données
● Extrait du fichier villes.csv"1";"Alsace";"Bas-Rhin";"Auenheim";"67480";"48.81313";"8.00982""2";"Alsace";"Bas-Rhin";"Bischwiller";"67240";"48.76712";"7.8604""3";"Alsace";"Bas-Rhin";"Dalhunden";"67770";"48.77566";"7.98999""4";"Alsace";"Bas-Rhin";"Drusenheim";"67410";"48.76468";"7.95021"
antislashn.org Android - La persistance des données 12 - 34/36
SQLite - exemple
● Le fichier csv est volumineux● il est renommé en csv.mp3 pour qu'il ne soit pas
compressé lors de la fabrication de l'APK– permet de sauter la barrière du 1 Mo– une autre manière de faire aurait été de casser le fichier en
fichiers de maximum 1 Mo● ceci n'est pas une bonne pratique
– import dans SQLite lent● environ 5 mn sur l'émulateur
– APK volumineux
antislashn.org Android - La persistance des données 12 - 35/36
SQlite - exemple
● La l'importation dans la base a lieu lors du premier lancement de l'activité FranceActivity ● l'utilisateur doit être patient
● Une ProgressDialog est affichée pour suivre la progression de l'import
● L'import est effectuée sur un thread secondaire par l'utilisation d'une classe qui étend AsyncTask● optimiser au mieux le code
– éviter de faire des logs lors de l'import– ne pas appeler publishProgress à chaque insertion en
base
antislashn.org Android - La persistance des données 12 - 36/36
SQlite - exemple
● Exemple d'interrogation de la basepublic List<Ville> getVillesByCP(String cp){
String[] columns = new String[]{VILLES_KEY_ID,VILLES_KEY_VILLE,VILLES_KEY_CP,VILLES_KEY_LATITUDE,VILLES_KEY_LONGITUDE};
String where = VILLES_KEY_CP + " LIKE ?";String[] params = new String[]{cp+"%"};
Cursor cursor = db.query(TABLE_VILLES, columns, where, params, null, null, null);List<Ville> villes = new ArrayList<Ville>();
cursor.moveToFirst();while(!cursor.isAfterLast()){
villes.add(new Ville(cursor.getInt(0),cursor.getString(1),cursor.getString(2),cursor.getDouble(3),cursor.getDouble(3)));
cursor.moveToNext();}
cursor.close();return villes;
}
antislashn.org Android - Les services 13 - 2/33
Service
● Composant applicatif indépendant● ne possède pas d'interface graphique● fournit une interface (au sens API) de communication
avec les autres composants applicatifs● hérite de la classe Context● l'exécution du service s'effectue dans le thread principal
de l'application● Utilisation d'un service
● directement● par établissement d'une connexion● ou un mixte des deux
antislashn.org Android - Les services 13 - 3/33
Service
● Le service est déclaré via le fichier manifeste● attribut name : classe du service
– comme une activité, peu commencer par un point si dans le package principal
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".SimpleServiceActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:label="HelloService" android:name=".HelloService"> <intent-filter> <action android:name="org.antislash.android.service.HELLO_SERVICE"/> </intent-filter> </service></application>
antislashn.org Android - Les services 13 - 4/33
Service
● Un service peut-être local ou distant (remote)● le service local n'est utilisable que par les activités de
l'application● Un service peut-être lancé et devenir "autonome"
● sans interaction avec l'activité qui l'a lancé– service de ping régulier par exemple
● si le service doit inter-agir avec l'activité il faut que l'activité connaisse les méthodes publiques du service– par une liaison au service (Bind)
– par utilisation de messages (Messenger)
– par un contrat AIDL (Android Interface Definition Language)● permet de faire de la communication inter-processus (IPC) en multi-
threading)
antislashn.org Android - Les services 13 - 5/33
Service
Application 1
Service
Activité 1-1 Activité 1-2
Application 2
Activité 2-1
le service démarrépar startService
le service est démarré par bindServicele service implémente onBind qui renvoie un Binder
le service présente un contrat AIDLservice est démarré par bindServicele service implémente onBind qui renvoie un Binder
antislashn.org Android - Les services 13 - 6/33
Service
● Le cycle de vie est différent si le service est lié ou non
antislashn.org Android - Les services 13 - 7/33
Service
● Démarrer le service depuis l'activité● appel de la méthode startService()
– invoque onCreate(), puis onStartCommand()– le service est alors démarré
● appel de la méthode bindService()– invoque uniquement la méthode onCreate()– le service est alors démarré et lié avec l'activité
● l'activité peut interagir avec lui à travers la connexion (Bind)
antislashn.org Android - Les services 13 - 8/33
Service
● Arrêt d'un service démarré par un startService● le système n'arrête pas un service sauf s'il a besoin de
mémoire● le service peut s'arrêter lui-même par un stopSelf● un autre composant peut arrêter un service par un
appel à stopService– le service n'est pas stoppé si d'autres composants sont
connectés au service
● Si le service a été démarré par un bindService le service est arrêté par un unbindService● le service est réellement détruit si plus aucun client
n'est lié au service
antislashn.org Android - Les services 13 - 9/33
Service
● Voir les services démarrés● dans le menu du téléphone
– Menu → Settings → Applications → Running Services
antislashn.org Android - Les services 13 - 10/33
Service – startService
● Démarrer le service avec startService()● méthode de la classe Activity● prend une intention en paramètre
– une intention explicite
– une intention implicite
– startService renvoie null si le service n'est pas démarré, sinon un ComponentName correspondant à un identifiant du composant
Intent intent = new Intent(this,PingService.class);startService(intent);
Intent intent = new Intent(".PingService.ACTION");startService(intent);
antislashn.org Android - Les services 13 - 11/33
Service – startService● Démarrer le service avec startService()
● le service est démarré de manière autonome● exemple de code de service
public class PingService extends Service {private Timer timer;
@Overridepublic void onCreate(){
super.onCreate();timer = new Timer();Log.d(this.getClass().getName(), "onCreate");
}
@Overridepublic int onStartCommand(Intent intent, int flags, int startId){
Log.d(this.getClass().getName(), "onStartCommand");timer.schedule(new TimerTask() {
@Overridepublic void run() {
Log.d(this.getClass().getName(), "FAIRE QUELQUE CHOSE D'UTILE ICI");}
}, 0,10000);return START_NOT_STICKY;
}... mode de redémarrage du service
antislashn.org Android - Les services 13 - 12/33
Service – startService
● Démarrer le service avec startService()● suite de l'exemple de la classe Service...
@Overridepublic void onDestroy(){
Log.d(this.getClass().getName(), "onDestroy");this.timer.cancel();
}
@Overridepublic IBinder onBind(Intent intent) {
return null;}
}
<service android:label="PingService" android:name=".PingService"> <intent-filter> <action android:name=".PingService.ACTION"/> </intent-filter> </service>
pas d'utilisation de connexion
antislashn.org Android - Les services 13 - 13/33
Service – bindService
● Pour créé un service connecté● le service doit implémenter la méthode onBind et
retourner un IBinder– le IBinder défini l'interface de communication avec le
service– la classe qui implémente IBinder possède une méthode
renvoyant une interface vers le service
antislashn.org Android - Les services 13 - 14/33
Service – bindService
● Code du service (extrait)
public class OperationsService extends Service implements IOperationService {private final OperationServiceBinder osBinder = new OperationServiceBinder();
public class OperationServiceBinder extends Binder{IOperationService getService(){
return OperationsService.this;}
}
@Overridepublic IBinder onBind(Intent intent) {
Log.d(this.getClass().getName(), ">> onBind()");return osBinder;
}...
antislashn.org Android - Les services 13 - 15/33
Service – bindService
● Pour démarrer et utiliser le service connecté● implémenter l'interface ServiceConnection
– possède des méthodes callback invoquées lors des connexions et déconnexions au service
– onServiceConnected permettra de récupérer une référence vers le service via la connexion
● l'appel de la méthode de déconnexion est effectuée si Android tue le service
● invoquer la méthode bindService– en lui passant une instance de l'implémentation de ServiceConnection
antislashn.org Android - Les services 13 - 16/33
Service - bindService
● Code de l'activité se connectant au service (extrait)public class ServiceBindingActivity extends Activity {
private boolean connecte = false;private IOperationService service;private ServiceConnection serviceConnection = new ServiceConnection() {
@Overridepublic void onServiceConnected(ComponentName name, IBinder binder) {
service = ((OperationServiceBinder)binder).getService();connecte = true;long r = service.add(1,2,3,4);Log.d(this.getClass().getName(), ">> onServiceConnected("+name+")");Toast.makeText(ServiceBindingActivity.this, "Appel du service : "+r,
Toast.LENGTH_SHORT).show();}@Overridepublic void onServiceDisconnected(ComponentName name) {
Log.d(this.getClass().getName(), ">> onServiceDisconnected("+name+")");connecte = false;
}}
...
antislashn.org Android - Les services 13 - 17/33
Service - bindService
● Code de l'activité se connectant au service (extrait)... public void bindService(View v){ Toast.makeText(this, "Bind service", Toast.LENGTH_SHORT).show(); Intent intent = new Intent("org.antislashn.android.service.OPERATIONS_SERVICE"); bindService(intent,serviceConnection,Context.BIND_AUTO_CREATE);} public void unbindService(View v){ Toast.makeText(this, "Unbind service", Toast.LENGTH_SHORT).show(); if(connecte) unbindService(serviceConnection);}...
antislashn.org Android - Les services 13 - 18/33
Service - bindService
● En résumé● Côté service
– créer l'interface du service– créer le service
● implémenter l'interface● étendre la classe Service
– ajouter une classe étendant de Binder● souvent une classe interne du service● avec une méthode retournant l'implémentation de l'interface du service
– implémenter la méthode onBind()● retourne une instance de Binder
– déclarer le service dans le manifeste
antislashn.org Android - Les services 13 - 19/33
Service - bindService
● En résumé● côté client (l'activité)
– créer une implémentation du listener ServiceConnection
– sur la méthode onServiceConnected● récupérer le service via le Binder
– appeler la méthode bindService(...) pour se connecter au service
– appeler la méthode unbindService(...) pour se déconnecter du service
antislashn.org Android - Les services 13 - 20/33
Service – exposition par AIDL
● Définition de l'interface du service● méthodes distantes accessibles● objets qui transitent entre le client et le serveur● la définition de l'interface est effectuée en AIDL
– Android Interface Definition Language● les paramètres doivent indiquer leur direction
– in : en entrée, paramètre passé du client vers le serveur
– out : en sortie, valeur fixée par le serveur et retournée au client
– inout : paramètre passé par le client vers le serveur, et pouvant être modifié par celui-ci avant retour vers le client
antislashn.org Android - Les services 13 - 21/33
Service – exposition par AIDL● Types des paramètres
● types primitifs java (boolean, byte, …)– en mode in par défaut, ne peuvent pas être out ou inout
● String : considéré comme un type primitif● CharSequence : considéré comme un type primitif● List
– le type des éléments doit être compatible avec les types AIDL
– la classe concrète utilisée est ArrayList
– la forme générique est utilisable, List<String> par ex.
● Map– le type des éléments doit être compatible avec les types AIDL
– la classe concrète utilisée est HashMap
– la forme générique n'est pas utilisable, Map<String,Integer> par ex.
antislashn.org Android - Les services 13 - 22/33
Service – exposition par AIDL
● Types de paramètres● type Parcelable● type définit à partir d'un autre AIDL
● Parcelable● interface caractérisant le support par une classe de la
fonctionnalité de marshalling/unmarshalling● doit définir un attribut statique CREATOR qui implémente
l'interface Parcelable.Creator– joue le rôle de factory de l'objet
● Les classes Parcelable doivent ● être déclarées dans un fichier aidl● être public final
antislashn.org Android - Les services 13 - 23/33
Service – exposition par AIDL
● Méthodes de Parcelable● int describeContents()
– retourne un masque de bits informant d'éventuels types particuliers manipulés par l'objet Parcelable
● documentation très peu explicite
– en général retourne la valeur zéro● void writeToParcel(Parcel dest, int flags)– écrit l'état de l'objet dans une parcelle– l'objet de type Parcel est un conteneur échangé avec un IBinder
● Parcel possède un ensemble de méthodes du type writeXxx et readXxx pour chacun des types
antislashn.org Android - Les services 13 - 24/33
Service – exposition par AIDL● Exemple d'objet Parcelable
public class Message implements Parcelable{private int numero;private String objet;private String corps;
public static final Parcelable.Creator<Message> CREATOR = new Creator<Message>() {@Overridepublic Message[] newArray(int size) {
return new Message[size];}@Overridepublic Message createFromParcel(Parcel source) {
Message message = new Message();message.numero = source.readInt();message.objet = source.readString();message.corps = source.readString();return message;
}};
@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {
dest.writeInt(numero);dest.writeString(corps);dest.writeString(objet);
}}
antislashn.org Android - Les services 13 - 25/33
Service – exposition par AIDL
● Fichier de déclaration des "parcelables"● dans un fichier aidl
● Définition du service● dans un fichier aidl
● Les fichiers sont détectés automatiquement par le plugin ADT
– génération des fichiers stub et proxy– l'outil aidl peut être exécuter en ligne de commande
● Puis codage du service● étend la classe Stub générée par l'outil aidl
antislashn.org Android - Les services 13 - 26/33
Service – exposition par AIDL
● Fichier AIDL du "parcelable"
● Fichier AIDL du service
package org.antislashn.android.service.aidl;parcelable Message;
package org.antislashn.android.service.aidl;
import org.antislashn.android.service.aidl.Message;
interface IMessageService{String echo(String name);Message createMessage(int numero, String objet, String corps);
}
implémentation du service
classe générée par le pluginou par l'outil aidl
antislashn.org Android - Les services 13 - 27/33
Service – exposition par AIDL
● Classe d'implémentation du service
import android.os.RemoteException;
public class MessageServiceImpl extends IMessageService.Stub{
public String echo(String name) throws RemoteException {return "Hello, "+name;
}
public Message createMessage(int numero, String objet, String corps) throws RemoteException {return null;
}}
antislashn.org Android - Les services 13 - 28/33
Service – exposition par AIDL
● Publication du service● le service est accessible via une intention qui est
envoyée● la classe d'implémentation du service peut aussi
embarquer la classe d'implémentation comme classe interne– le service et la classe d'implémentation sont indépendantes
public class MessageService extends Service {private final MessageServiceImpl service = new MessageServiceImpl();
@Overridepublic IBinder onBind(Intent intent) {
return service;}
}
antislashn.org Android - Les services 13 - 29/33
Service – exposition par AIDL
● Déclaration du service dans le manifeste<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.antislashn.android.service.aidl" android:versionCode="1" android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <service android:name=".MessageService" android:exported="true"> <intent-filter> <action android:name="org.antislashn.android.service.MESSAGE_SERVICE"/> </intent-filter> </service> </application>
</manifest>
antislashn.org Android - Les services 13 - 30/33
Service – exposition par AIDL
● Résumé : phases de mise en place● définition du service dans le fichier .aidl
– l'outil aidl générera la classe Stub– si des objets "parcelables" sont utilisés ils doivent être
déclarés dans un fichier .aidl● implémentation du service par spécialisation de la
classe Stub générée● publication du service par spécialisation de la classe Service– le onBind renvoie une instance de la classe d'implémentation
– la classe d'implémentation peut-être une classe interne
antislashn.org Android - Les services 13 - 32/33
Service – exposition par AIDL
● Consommation du service● le client doit avoir accès à l'interface du service
– les classes sont dans des applications séparées– il faut donc mettre le fichier AIDL dans le répertoire src du
client● lors de l'appel de la méthode callback onServiceConnected le client doit obtenir le service via la méthode Stub.asInterface(...) de l'interface du service
● l'intention utilisée pour se connecter au service doit utiliser un nom d'action plutôt que le nom de la classe– la classe n'est généralement pas connue par le client
antislashn.org Android - Les services 13 - 33/33
Service – exposition AIDL
● Code du client du service AIDL (extrait)public class ClientServiceAidlActivity extends Activity {
private boolean connecte = false;private IMessageService service;private ServiceConnection serviceConnection = new ServiceConnection() {
@Overridepublic void onServiceConnected(ComponentName name, IBinder binder) {
service = IMessageService.Stub.asInterface(binder);connecte = true;try {
String r = service.echo("Franck");Toast.makeText(ClientServiceAidlActivity.this, "Appel du service : "+r,
Toast.LENGTH_SHORT).show();} catch (RemoteException e) {
Log.e(this.getClass().getName(),"ERREUR SUR echo()", e);}
}
@Overridepublic void onServiceDisconnected(ComponentName name) {
connecte = false;}
};...
antislashn.org Android - Les fournisseurs de contenu 14 - 1/25
Les fournisseurs de contenuContentProvider
antislashn.org Android - Les fournisseurs de contenu 14 - 2/25
Fournisseurs de contenus
● Permet le partage public des données● par défaut Android expose plusieurs fournisseurs de
contenus– contacts personnels, images, vidéos, audio, ...
● Chaque application peut alors lire et modifier les données d'une autre application● sous réserve d'avoir les droits nécessaires
● Tous les fournisseurs exposent une interface commune
● Chaque fournisseur fournit une URI par table de données● il y a autant d'URI que de tables de données
antislashn.org Android - Les fournisseurs de contenu 14 - 3/25
Fournisseurs de contenus
● Le fournisseur de contenu retourne les données sous forme de table● quelque soit le mode de de stockage réel● chaque ligne retournée correspond à un enregistrement● chaque champ correspond à une colonne● chaque enregistrement possède un identifiant
numérique unique _ID● Syntaxe des URI
● content://domaine.nomFournisseur● content://domaine.nomFournisseur/id● content://domaine.nomFournisseur/sous-chemin● content://domaine.nomFournisseur/sous-chemin/id
antislashn.org Android - Les fournisseurs de contenu 14 - 4/25
Fournisseurs de contenus
● Syntaxe des URI● content:// : pseudo protocole● domaine.nomFournisseur : partie autorité de l'URI
– exemple : org.antislashn.todos● sous-chemin : permet au fournisseur de déterminer le
type de données● id : identifiant unique _ID de l’enregistrement
– vide si la requête concerne plusieurs enregistrements
● Android fournit des URI pour ses fournisseurs de contenu
antislashn.org Android - Les fournisseurs de contenu 14 - 5/25
Fournisseurs de contenus
● Exemple : le fournisseur de contenu Android pour les contacts
● ContactsContract.Contacts.CONTENT_URI– CONTENT_URI : constante définissant l'URI réelle
● tout fournisseur de contenu devrait créer cette propriété constante statique pour une meilleur lisibilité et une meilleure maintenance
antislashn.org Android - Les fournisseurs de contenu 14 - 6/25
Fournisseurs de contenus
● Exemple : lecture du nom des contactsUri uri = ContactsContract.Contacts.CONTENT_URI;ContentResolver cr = this.getContentResolver();Cursor cursor = cr.query(uri, null, null, null, null);if(cursor.moveToFirst()){
String name;String phoneNumber;int numColName = cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME);do{
name = cursor.getString(numColName);Log.d(this.getClass().getName(),name);
}while(cursor.moveToNext());}
récupération du numéro de colonne
<uses-permission android:name="android.permission.READ_CONTACTS"/>
permission à ajouter dans le manifeste
accès à la résolution desfournisseurs de contenus
antislashn.org Android - Les fournisseurs de contenu 14 - 7/25
Fournisseurs de contenus
● La classe ContentResolver permet d'utiliser un fournisseur de contenus● effectuer des requêtes, récupérer des données, …● la méthode getContentResolver de la classe Context permet de récupérer un ContentResolver
● la classe ContentResolver contient des méthodes pour– interroger : query(...)
– supprimer : delete(...)
– mettre à jour : update(...)
– ajouter : insert(...)– etc.
antislashn.org Android - Les fournisseurs de contenu 14 - 8/25
Les fournisseurs de contenus Android
● Android fournit nativement des ContentProvider● l'utilisation du package android.provider simplifie l'accès
aux ContentProvider– Browser : accès aux bookmarks, historiques, …
– CallLog : accès au journal des appels
– ContactsContract : accès aux contact
– MediaStore : accès aux contenus multimédia
– Settings : accès aux réglages du téléphone
– UserDictionnary : accès au dictionnaire IME (Input Method)
antislashn.org Android - Les fournisseurs de contenu 14 - 9/25
Test du provider multimédia
● Ajouter du contenu multimédia sur la SDcard de l'émulateur● sous Eclipse, simplement faire un copier-coller du
fichier vers le File Explorer de l'émulateur● en mode console utiliser
– adb push <filename> /sdcard
● déclencher la mise à jour des contenus multimédias sur l'émulateur– application Dev Tools– Media Scanner
antislashn.org Android - Les fournisseurs de contenu 14 - 10/25
Test du provider multimédias
● Les URI sont de la forme
● <mediatype> : Audio, Image ou Video● avec sauvegarde en interne (téléphone) ou externe
(SDcard)
MediaStore.<mediatype>.Media.EXTERNAL_CONTENT_URIMediaStore.<mediatype>.Media.INTERNAL_CONTENT_URI
antislashn.org Android - Les fournisseurs de contenu 14 - 11/25
Test du provider multimedia
● Extrait de code – projet Audio Content Providerpublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,null,null,null); startManagingCursor(cursor); int idIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID); int titleIdx = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE); int albumIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM); int artistIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST); String title; String album; String artist; int id ; if(cursor.moveToFirst()) do{ title = cursor.getString(titleIdx); album = cursor.getString(albumIdx); artist = cursor.getString(artistIdx); id = cursor.getInt(idIdx); Log.d(this.getClass().getCanonicalName(),">>> "+id+" : "+artist+" - "+album+" - "+title); }while(cursor.moveToNext()); }
URI
l'activité gère le cycle de vie du curseur
récupération des index de colonnes
antislashn.org Android - Les fournisseurs de contenu 14 - 12/25
Test du ContactsProvider
● Ce provider est une base de données extensible● le ContactsContract provider utilise un modèle de
gestion de données– association d'un contact et d'une agrégation associée à une
seule personne, ● Data : chaque colonne de data est une données personnelles
– téléphone, email, …– lié à un type MIME
● RawContact : gestion des comptes d'un contact– Google +, Gmail, Facebook, …
● Contacts : agrégation de RawContact se rapportant à une personne
antislashn.org Android - Les fournisseurs de contenu 14 - 13/25
Test du ContactsProvider
● L'utilisation de ContactsContract nécessite des permissions
●
<uses-permission android:name="android.permission.READ_CONTACTS" /><uses-permission android:name="android.permission.WRITE_CONTACTS" />
antislashn.org Android - Les fournisseurs de contenu 14 - 14/25
Test du Contact Provider
● Exemple : lecture du nom des contactsUri uri = ContactsContract.Contacts.CONTENT_URI;ContentResolver cr = this.getContentResolver();Cursor cursor = cr.query(uri, null, null, null, null);if(cursor.moveToFirst()){
String name;String phoneNumber;int numColName = cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME);do{
name = cursor.getString(numColName);Log.d(this.getClass().getName(),name);
}while(cursor.moveToNext());}
récupération du numéro de colonne
<uses-permission android:name="android.permission.READ_CONTACTS"/>
permission à ajouter dans le manifeste
antislashn.org Android - Les fournisseurs de contenu 14 - 15/25
Création d'un fournisseur de contenu
● L'exemple développé ici reprend le projet Eclispe "France ContentProvider "● il utilise une base de données importante
– chargement d'environ 5 minutes sur l'émulateur– donc inconcevable dans la réalité...
● il utilise une classe FranceDAO qui cache les détails d'implémentation d'utilisation de la base
antislashn.org Android - Les fournisseurs de contenu 14 - 16/25
Création d'un fournisseur de contenu
● Etapes de création d'un fournisseur de contenu1.spécialiser la classe ContentProvider2.créer l'URI associée au fournisseur de contenu3.créer la base de données sous-jacente au fournisseur
de contenu4.créer un UriMatcher qui déclare l'utilisation des URI5.redéfinir la méthode getType qui retourne le type
MIME associé aux URI6.redéfinir la méthode onCreate afin de créer un SQLiteOpenHelper
7.coder les méthodes de gestion de la base de données8.déclarer le fournisseur de contenu dans le manifeste
antislashn.org Android - Les fournisseurs de contenu 14 - 17/25
Création d'un fournisseur de contenuÉtape 1
● Classe dérivée de ContentProviderpublic class FranceProvider extends ContentProvider {
@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) { return 0;}
@Overridepublic String getType(Uri uri) { return null; }
@Overridepublic Uri insert(Uri uri, ContentValues values) { return null;}
@Overridepublic boolean onCreate() {return false;}
@Overridepublic Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {return null;
}
@Overridepublic int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {return 0;
}}
antislashn.org Android - Les fournisseurs de contenu 14 - 18/25
Création d'un fournisseur de contenuÉtapes 2 et 3
● Création de l'URI associée au provider● dans notre classe dérivée de ContentProvider● cette URI sera utilisée par les autres application pour
accéder à notre fournisseur de contenu
● Création de la base de données● cf la création des bases de données● créer les constantes publiques pour les noms et les
index de colonne– dans notre exemple la classe FranceDAO
public static final Uri CONTENT_URI =Uri.parse("content://org.antislahn.provider.france/villes");
antislashn.org Android - Les fournisseurs de contenu 14 - 19/25
Création d'un fournisseur de contenuÉtape 4
● Création d'un UriMatcher dans la classe dérivée de ContentProvider● pour des requêtes renvoyant plusieurs résultat (VILLES) ou
un seul (VILLE_ID)● la méthode addURI prend trois paramètres
– autorithy : classiquement le nom de la classe du fournisseur● fait référence à l'attribut autorithy du fichier manifeste
– path : le chemin à reconnaître, peut comprendre les jokers * (tout texte) ou # (numérique)
– code : code à retourner si l'URI est reconnue, entier positifprivate static final int VILLES = 1;private static final int VILLE_ID = 2;private static final UriMatcher uriMatcher;static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);uriMatcher.addURI("org.antislahn.provider.france", "villes", VILLES);uriMatcher.addURI("org.antislahn.provider.france", "villes/#", VILLE_ID);
}
antislashn.org Android - Les fournisseurs de contenu 14 - 20/25
Création d'un fournisseur de contenuÉtape 5
● Redéfinition de la méthode getType● retourne une String pour chaque URI supportée
– le type MIME● doit commencer par
– vnd.android.cursor.dir des résultats multiples– vnd.android.cursor.item pour un résultat unique
@Overridepublic String getType(Uri uri) {
switch(uriMatcher.match(uri)){case VILLES : return "vnd.android.cursor.dir/vnd.antislashn.france";case VILLE_ID : return "vnd.android.cursor.item/vnd.antislashn.france";default : throw new IllegalArgumentException("Unsupported URI : "+uri);
}}
antislashn.org Android - Les fournisseurs de contenu 14 - 21/25
Création d'un fournisseur de contenuÉtape 6
● Redéfinir la méthode onCreate● création d'une nouvelle instance de la classe de gestion
de la base de donnée
@Overridepublic boolean onCreate() {
boolean result = false;try{
dao = new FranceDAO(getContext(), null, null);result = true;
}catch (Exception e) {
Log.e(FranceActivity.class.getCanonicalName(), ">>>> EXCEPTION", e);}return result;
}
dao est une propriété de la classe FranceProvider
antislashn.org Android - Les fournisseurs de contenu 14 - 22/25
Création d'un fournisseur de contenuÉtape 7
● codage des méthodes de gestion de la base de données sous-jacente● méthodes query, insert, update, delete● commencer avec la méthode query qui doit décoder la
requête et retourner un Cursor● voir le code sur le slide suivant
antislashn.org Android - Les fournisseurs de contenu 14 - 23/25
Création d'un fournisseur de contenuÉtape 7
● Code de la méthode query@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sort) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();qb.setTables(dao.TABLE_VILLES);switch(uriMatcher.match(uri)){
case VILLE_ID: qb.appendWhere((dao.VILLES_KEY_ID+"="+uri.getPathSegments().get(1)));break;
default:break;
}String orderBy;if(TextUtils.isEmpty(sort)){
orderBy = dao.VILLES_KEY_VILLE;}else{
orderBy = sort;}
Cursor c = qb.query(dao.getDataBase(), projection, selection, selectionArgs, null, null, orderBy);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;}
antislashn.org Android - Les fournisseurs de contenu 14 - 24/25
Création d'un fournisseur de contenuÉtape 8
● Déclarer le fournisseur dans le fichier manifeste<provider android:name=".FranceProvider" android:authorities="org.antislahn.provider.france" />
antislashn.org Android - Les fournisseurs de contenu 14 - 25/25
Utilisation du fournisseur de contenu
● Retrouver tous les enregistrements du provider
● enverra l'URI● Retrouver un enregistrement par un _ID
● enverra l'URI● Retrouver des enregistrements par critère
● enverra l'URL– et ajoutera une clause where à l'appel de query du provider
Cursor cursor = getContentResolver().query(FranceProvider.CONTENT_URI, null, null, null, null);
content://org.antislahn.provider.france/villes
Uri uri = ContentUris.withAppendedId(FranceProvider.CONTENT_URI, 10); Cursor cursor = getContentResolver().query(uri, null, null, null, null);
content://org.antislahn.provider.france/villes/10
String cp = ((EditText)findViewById(R.id.cp)).getText().toString();String where = FranceDAO.VILLES_KEY_CP+ " LIKE '"+cp+"%'";Cursor cursor = getContentResolver().query(FranceProvider.CONTENT_URI, null, where, null, null);
content://org.antislahn.provider.france/villes
antislashn.org Android - BroadcastReceiver 15 - 2/11
Réception d'événements
● Les événements sont des Intent● Classe qui permet de réagir à des changements
d'état● de l'appareil lui même
– mise en veille, démarrage, boot fini, etc.● d'applications entre elles● d'un service vers une activité
– le service ne peut pas interagir directement avec l'IHM de l'activité
● Cette classe réagit à des intentions envoyées par sendBroadcast()
antislashn.org Android - BroadcastReceiver 15 - 3/11
Réception d'événements
● Deux types principaux de récepteurs● BroadcastReceiver
– à l'écoute de tous les événements● appareil ou application
● LocalBroadcastReceiver– à l'écoute des événements dans une même application
● peut nécessiter android.support.v4
– les messages envoyés seront locaux● via la classe LocalBroadcastManager
– meilleures sécurité et efficacité
● Une méthode de réception● onReceive(Context context, Intent intent)
antislashn.org Android - BroadcastReceiver 15 - 4/11
Réception d'événements
● Le récepteur peut être déclaré dans le fichier AndroidManifest.xml● spécialise un BroadcastReceiver
– ou une autre sous classe● WakefulBroadcastReceiver● DeviceAdminReceiver● AppWidgetProvider
● souvent plus simple pour réagir aux actions standards– par exemple : permet de déclencher un service lorsque
l'appareil a complètement démarré● ACTION_BOOT_COMPLETED● voir aussi la classe WakefulBroadcastReceiver
● Le récepteur peut aussi être enregistré à la demande
antislashn.org Android - BroadcastReceiver 15 - 5/11
Réception d'événements
● Le récepteur peut aussi être enregistré à la demande● permet de faire interagir un service sur une activité● l'activité inscrit et désinscrit le récepteur auprès du LocalBroadcastManager
● pas d'enregistrement du récepteur das le fichier manifeste
antislashn.org Android - BroadcastReceiver 15 - 6/11
Exemple de filtre de SMS
● Certains SMS sont filtrés par un BroadcastReceiver pour un traitement spécifique● dont l'origine est le numéro de téléphone 0123456789● la chaîne des récepteurs est alors abandonnée
● Déclaration du récepteur dans le fichier manifeste● la priorité est élevée pour que notre récepteur soit le
premier de la chaîne
<receiver android:name=".SmsFilterBroadcastReceiver" android:exported="true"><intent-filter android:priority="100" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" /></intent-filter>
</receiver>
antislashn.org Android - BroadcastReceiver 15 - 7/11
Exemple de filtre de SMS
● Code du récepteur
public class SmsFilterBroadcastReceiver extends BroadcastReceiver {static final String ACTION_FILTREE = "android.provider.Telephony.SMS_RECEIVED";
@Overridepublic void onReceive(Context context, Intent intent) {
if (intent.getAction().equalsIgnoreCase(ACTION_FILTREE)){Bundle bundle = intent.getExtras();if (bundle != null){
Object[] pdus = (Object[]) bundle.get("pdus");SmsMessage sms = SmsMessage.createFromPdu((byte[])pdus[0]);String tel = sms.getOriginatingAddress();if(tel.equals("0123456789")){
Toast.makeText(context,tel+" : "+sms.getMessageBody(),Toast.LENGTH_LONG).show();
this.abortBroadcast();}
}}
}}
antislashn.org Android - BroadcastReceiver 15 - 8/11
Exemple de filtre de SMS
● Mise en place des permissions dans le fichier manifeste
<uses-permission android:name="android.permission.RECEIVE_SMS" /><uses-permission android:name="android.permission.READ_SMS" />
antislashn.org Android - BroadcastReceiver 15 - 9/11
Exemple de gestion du récepteur par l'activité
● Un service doit mettre à jour un widget de l'activité● le service est dans la même application● le service n'a pas accès au widget● il envoi un Intent par le LocalBroadcastManager● extrait de code
public class YahooInterrogationService extends Service {private LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
...@Overridepublic int onStartCommand(Intent intent,int flags, int startId){...
timer.schedule(new TimerTask() {@Overridepublic void run() {
...Intent intent = new Intent(MainActivity.FILTER);intent.putExtra("value", responseBody);broadcastManager.sendBroadcast(intent);...
}}, 0,10000);
return Service.START_STICKY;}
}
antislashn.org Android - BroadcastReceiver 15 - 10/11
Exemple de gestion du récepteur par l'activité
● L'activité crée le récepteur et lance le service● extrait de code
public class MainActivity extends Activity {...
public static final String FILTER = "org.antislashn.android.FILTRE";private BroadcastReceiver receiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);...receiver = new BroadcastReceiver() {
@Overridepublic void onReceive(Context context, Intent intent) {
String val = intent.getStringExtra("value");...
}};Intent intent = new Intent(this, YahooInterrogationService.class);intent.putExtra("name", "GOOG");startService(intent);
}...
antislashn.org Android - BroadcastReceiver 15 - 11/11
Exemple de gestion du récepteur par l'activité
● L'activité gère l'enregistrement du récepteur● extrait de code
...@Overrideprotected void onStart(){
super.onStart();LocalBroadcastManager.getInstance(this).registerReceiver(receiver, new IntentFilter(FILTER));
}
@Overrideprotected void onStop(){
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);super.onStop();
}...
antislashn.org Android - Processus et threads 16 - 2/12
Processus
● Par défaut toute application est lancée dans son propre processus● au lancement du premier composant d'une application
un processus Linux est créé● dans le processus une machine virtuelle Dalvik est
lancée– le composant est lancé dans la MV sur un thread principal
● Avec la commande adb, il est possible de voir les processus● adb shell● ps
antislashn.org Android - Processus et threads 16 - 3/12
Processus
● Le processus prend le nom du package de l'application● le nom peut être modifié avec l'attribut android:process
– garder la même convention de nommage que les packages● par défaut tous les composants s'exécutent dans le
même processus– et dans le même thread principal
● un composant peut changer cette règle– préciser l'attribut android:process avec un nouveau nom
● si le nom est précédé par deux points (:) le processus est privé à l'application
antislashn.org Android - Processus et threads 16 - 4/12
Processus
● Exemple : deux activités lancées dans le même processus
● Exemple : deux activités lancées dans des processus différents
<activity android:process=":autre" android:label="@string/app_name" android:name=".AutreActivite" ></activity>
antislashn.org Android - Processus et threads 16 - 5/12
Processus
● Si plusieurs applications partagent le même nom de processus elles partagent le même processus● permet de partager les mêmes ressources
– fichier, mémoire, préférences, …● les applications doivent utiliser
– android:process avec le nom du processus
– android:sharedId avec un même nom d'identifiant● le nom doit au moins contenir un point● en général utiliser la convention des noms de package
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.antislashn.android.processus" android:versionCode="1" android:versionName="1.0" android:sharedUserId="org.antislashn.android.processus.user1">
antislashn.org Android - Processus et threads 16 - 6/12
Thread
● Un processus ne comprend qu'un seul thread● ce thread est important :
– gestion des événements, affichage des GUI, traitements programmés dans les composants applicatifs
● Si au bout de 10 secondes une application est considérée comme bloquée par Android● l'utilisateur peut alors la tuer
antislashn.org Android - Processus et threads 16 - 7/12
Thread
● Tout traitement long doit donc s'effectuer dans un thread secondaire● utilisation de Runnable et Thread● utilisation de Handler● utilisation de AsyncTask
● AsyncTask simplifie la gestion des threads● façon simple d'exécuter un thread et d'afficher un
résultat● permet de ne pas manipuler directement les threads
– gère la création et la communication entre les threads
antislashn.org Android - Processus et threads 16 - 8/12
AsyncTask
● Fournit des méthodes de rappels● onPreExecute : initialisation du traitement
– invoquée depuis le thread principal
● doInBackground : exécution du traitement– invoquée depuis le thread secondaire
● onProgressUpdate : progression du traitement– invoquée depuis le thread principal
● onPostExecute : fin du traitement– invoquée depuis le thread principal
● pour arrêter la tâche : cancel
antislashn.org Android - Processus et threads 16 - 9/12
AsyncTask
● Prend trois types génériques● Params : type des paramètres fournis à la tâche● Progress : type de l'unité de progression du
traitement● Result : type du résultat du traitement
antislashn.org Android - Processus et threads 16 - 10/12
AsyncTask
● Utilisation● créer la classe étendant AsyncTask
– souvent une classe interne du composant applicatif
● instancier la classe qui étend AsyncTask● invoquer la méthode execute sur l'instance de type AsyncTask
● Une tâche n'est traitée qu'une seule fois● il faut instancier une nouvelle tâche pour relancer un
nouveau traitement
antislashn.org Android - Processus et threads 16 - 11/12
AsyncTask● Exemple de codepublic class TraitementLong extends AsyncTask<Integer, Integer, Integer>{
@Overrideprotected void onPreExecute(){
super.onPreExecute();Log.d(this.getClass().getName(),"protected void onPreExecute()");
}
@Overrideprotected Integer doInBackground(Integer... params) {
int resultat = 0;Log.d(this.getClass().getName(),"protected Integer doInBackground(Integer... params)");for(int i=0 ; i<100 ; i++){
try {Thread.sleep(100);
} catch (InterruptedException e) {}publishProgress(i);resultat++;
}return resultat;
}
@Overrideprotected void onProgressUpdate(Integer... values){
super.onProgressUpdate(values);Log.d(this.getClass().getName(),"protected void onProgressUpdate(Integer... values)");String m = values[0]+"%";tvAvancement.setText(m);
}@Overrideprotected void onPostExecute(Integer result){
super.onPostExecute(result);Log.d(this.getClass().getName(),"protected void onPostExecute(Integer result)");
} }
invoquée avant l'exécution du thread secondaire
traitement long dans le thread secondaire
appel de onProgressUpdate
invoquée par publishProgress
invoquée après l'exécution du thread secondaire
antislashn.org Android - Processus et threads 16 - 12/12
AsyncTask
● Lancement de la tâche● execute(...) reçoit les paramètres qui seront utilisés
par doInBackground
TraitementLong tl = new TraitementLong();tl.execute(100);
antislashn.org Android - Application Widget 17 - 2/15
App Widgets
● Le widget est placé sur l'un des bureaux du téléphone● il peut prendre plus de place qu'un raccourci vers une
application● les informations qu'il affiche peuvent être mises à jour
périodiquement– méthode déclarative par le fichier XML– méthode programmatique par le service AlarmManager
antislashn.org Android - Application Widget 17 - 3/15
App Widgets
● Exemples de widgets● écoute de musique● horloge analogique● recherche dans les contacts
● Les widgets s'installent via un appui long sur le bureau
antislashn.org Android - Application Widget 17 - 4/15
App Widgets● Un widget est construit sur des composants
● un AppWidgetProvider– sa méthode onUpdate(...) permet de mettre à jour l'IHM
du widget lors des appels par Android● installation sur le bureau, ou appel régulier par déclaration d'un délai
dans le fichier info.xml, cf. android:updatePeriodMillis
– spécialisation de BroadcastReicever
● un RemoteViews pour la création de l'IHM– peut-être exécuté par un autre processus
● le BroadcastReicever transforme (inflate) le layout du widget en un objet de type RemoteViews
● Le processus qui accueille la partie visuelle du App Widget est nommée App Widget host.
antislashn.org Android - Application Widget 17 - 5/15
Etapes de création d'un App Widget
1.définition de l'IHM2.créer le fichier de configuration du App Widget3.créer un classe dérivant de AppWidgetProvider4.déclarer cette classe dans le fichier manifeste5.facultatif : créer un activité qui sera appelée lors de
l'ajout du widget au bureau
antislashn.org Android - Application Widget 17 - 6/15
Exemple HorlogeWidget
● Affichage périodique de l'heure● intervalle de mise à jour du widget est fixe
● Lors de la création du projet, décochez la mise en place d'une activité
antislashn.org Android - Application Widget 17 - 7/15
HorlogeWidget – étape 1
● Création de l'IHM● créer le fichier res/layout/horloge_widget.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <TextView android:id="@+id/tvHeures" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="HH" android:textAppearance="?android:attr/textAppearanceMedium" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=":" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/tvMinutes" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="mm" android:textAppearance="?android:attr/textAppearanceLarge" /></LinearLayout>
antislashn.org Android - Application Widget 17 - 8/15
HorlogeWidget – étape 2
● Fichier de configuration du widget● créer un fichier res/xml/horloge_widget_info.xml● utilisez l'assistant
antislashn.org Android - Application Widget 17 - 9/15
HorlogeWidget – étape 2
● Passez en mode "Structure" pour afficher l'assistant de saisie
antislashn.org Android - Application Widget 17 - 10/15
HorlogeWidget – étape 2● Contenu du fichier res/xml/horloge_widget_info.xml
● le délai entre deux appels ne peut pas être inférieur à 30 minutes – ceci peut-être contourné en utilisant le service AlarmeManager
● attention de toujours avoir le soucis d'économiser la vie de la batterie– pas de mise à jour trop fréquente
● en mettant à 0 updatePeriodMillis la méthode onUpdate() n'est pas appelée régulièrement<?xml version="1.0" encoding="utf-8"?><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/horloge_widget" android:minHeight="72dp" android:minWidth="146dp" android:updatePeriodMillis="1800000" >
</appwidget-provider>
antislashn.org Android - Application Widget 17 - 11/15
HorlogeWidget – étape 2
● Un écran Android contient 16 cellules● 4 par 4● une icône par cellule
● Un widget peut s'étaler sur plusieurs cellules● Le calcul peut s'effectuer par
● taille = (Nb cellules * 74dp) – 2 dp
antislashn.org Android - Application Widget 17 - 12/15
HorlogeWidget - étape 3
● Création de la classe AppWidgetProviderpublic class HorlogeWidgetProvider extends AppWidgetProvider {
@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){Log.d(this.getClass().getCanonicalName(),">>>> onUpdate");for(int i=0 ; i<appWidgetIds.length; i++){
int id = appWidgetIds[i];RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.horloge_widget);Time time = new Time();time.setToNow();String h = Integer.toString(time.hour);String mn = Integer.toString(time.minute);views.setTextViewText(R.id.tvHeures, h);views.setTextViewText(R.id.tvMinutes, mn);appWidgetManager.updateAppWidget(id, views);}
}}
antislashn.org Android - Application Widget 17 - 13/15
HorlogeWidget - étape 3● La méthode onUpdate(...) reçoit l'ensemble des
widgets à mettre à jour● un même App Widget peut-être ajouté plusieurs fois à
l'écran– il faut donc mettre à jour l'ensemble des IHM de ce widget
● Les autres méthodes intéressantes● onDelete(Context context, int[] appWidgetIds)
– invoquée sur ACTION_APPWIDGET_DELETED
● onDisable(Context context)– invoquée sur ACTION_APPWIDGET_DISABLE
● onEnable(Context context, Intent intent)– invoquée sur ACTION_APPWIDGET_ENABLE
● onReceive(Context context, Intent intent)
antislashn.org Android - Application Widget 17 - 14/15
HorlogeWidget - étape 4
● Modifier le fichier manifeste<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.antislashn.android.widget.horloge" android:versionCode="1" android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <receiver android:name="HorlogeWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/horloge_widget_info"/> </receiver> </application>
</manifest>
antislashn.org Android - Application Widget 17 - 15/15
HorlogeWidget - étape 4
● La classe HorlogeWidgetProvider est abonnée à l'événement android.appwidget.action.APPWIDGET_UPDATE● l'abonnement à cet événement est obligatoire● il y a aussi des notifications pour
– ACTION_APPWIDGET_DELETED– ACTION_APPWIDGET_ENABLE– ACTION_APPWIDGET_DISABLE
● La balise <meta-data> référencie le fichier de configuration du widget
antislashn.org Android - Les fragments 18 - 2/28
Les fragments
● Existent depuis Android 3.0● API niveau 11
● Un fragments représente une portion d'activité● portion d'une IHM● portion d'un comportement
● Permet la réutilisation d'un fragment dans des activités● ajout statique ou dynamique● permet de mieux gérer les écrans de tailles différentes
● Le fragment est embarqué dans une activité et suit le cycle de vie de l'activité
antislashn.org Android - Les fragments 18 - 3/28
Design avec les fragments
● Une application peut utiliser● un fragment pour afficher une liste● un fragment pour afficher les détails des éléments d'une
liste
source : Google
antislashn.org Android - Les fragments 18 - 4/28
Design avec les fragments
● Dans l'application précédente● sur une tablette l'activité A contient les fragments A et B● sur le téléphone l'activité A contient le fragment A et
l'activité B contient le fragment B– l'activité B n'est jamais utilisée sur une tablette
● Le comportement de l'application dépendra de la configuration● si le fragment B est contenu dans le layout, l'activité A
notifie le fragment B de se mettre à jour● sinon l'activité A démarre l'activité B
antislashn.org Android - Les fragments 18 - 5/28
Design avec les fragments
● Il est important● de ne jamais manipuler un fragment directement depuis
un autre● de coder le comportement du fragment dans le
fragment et non pas dans l'activité● Pour éviter les appels directs
● définir une interface callback dans chaque fragment● implémenter l'interface au niveau de l'activité
antislashn.org Android - Les fragments 18 - 6/28
Exemple SimpleFragment
● Le projet SimpleFragment montre comment ajouter un fragment
● Le fragment est constitué● d'un fichier xml décrivant l'IHM du fragment● d'une classe de gestion du fragment
– la vue est créée dans la méthode onCreateView()
● L'ajout du fragment est ici statique● effectué dans le fichier xml de l'IHM de l'activité
principale
antislashn.org Android - Les fragments 18 - 7/28
Exemple SimpleFragment
● Fragment● fichier layout/fragment.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Clic" />
</LinearLayout>
antislashn.org Android - Les fragments 18 - 8/28
Exemple SimpleFragment
● Fragment● code de gestion du fragment
public class SimpleFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment, container,false);
Button button = (Button) view.findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {public void onClick(View v) {
Toast.makeText(getActivity(), "Clic !!!", Toast.LENGTH_LONG).show();}
});
return view;}
}
antislashn.org Android - Les fragments 18 - 9/28
Exemple SimpleFragment
● Activité<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<fragment android:id="@+id/simple_fragment" android:name="org.antislashn.android.fragments.SimpleFragment" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
</LinearLayout>
public class SimpleFragmentMainActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
antislashn.org Android - Les fragments 18 - 10/28
Exemple SimpleDynamicFragment
● Le projet montre comment ajouter dynamiquement un fragment
● Le fragment est le même que dans l'exemple précédent
● L'activité utilise le FragmentManager pour ajouter dynamiquement le fragment● via la méthode getFragmentManager()● ou la méthode getSupportFragmentManager() si
utilisation de la librairie de rétro compatibilité
antislashn.org Android - Les fragments 18 - 11/28
Exemple SimpleDynamicFragment
● Activité● fichier layout/main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" >
<FrameLayout android:id="@+id/fragment" android:layout_width="match_parent" android:layout_height="match_parent" />
</RelativeLayout>
le fragment sera injecté dansle FrameLayout
antislashn.org Android - Les fragments 18 - 12/28
Exemple SimpleDynamicFragment
● Activitépublic class MainActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentManager fm = getFragmentManager(); Fragment fragment = fm.findFragmentById(R.id.fragment); if(fragment == null){ FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.fragment, new SimpleFragment()); ft.commit(); } }}
les opérations sur les fragmentssont effectuées dans une transaction
antislashn.org Android - Les fragments 18 - 13/28
Exemple Multi Materiels Fragment
● En fonction du matériel les vues seront différentes mais les fragments seront les mêmes
● Le projet est organisé afin d'utiliser des layouts différents selon le matériel
layout utilisé par l'activité principaledu téléphone
layout utilisé par l'activité principalede la tablette
layouts utilisés par tous les matériels
antislashn.org Android - Les fragments 18 - 14/28
Exemple Multi Materiels Fragment
● Layout de l'activité principale pour un téléphone● un seul fragment de chargé
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<fragment android:id="@+id/fragment_a" android:name="org.antislashn.android.fragments.FragmentA" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
</LinearLayout>
antislashn.org Android - Les fragments 18 - 15/28
Exemple Multi Materiels Fragment
● Layout de l'activité principale pour une tablette● deux fragments chargés
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" >
<fragment android:id="@+id/fragment_a" android:name="org.antislashn.android.fragments.FragmentA" android:layout_width="200dp" android:layout_height="fill_parent"/> <fragment android:id="@+id/fragment_b" android:name="org.antislashn.android.fragments.FragmentB" android:layout_width="wrap_content" android:layout_height="fill_parent"/>
</LinearLayout>
antislashn.org Android - Les fragments 18 - 16/28
Exemple Multi Materiels Fragment
● Un fragment (FragmentA) comporte● une zone de saisie● un bouton
● Un fragment (FragmentB) comporte● un libellé
● Le clic sur le bouton de FragmentA doit mettre à jour le libellé de FragmentB
antislashn.org Android - Les fragments 18 - 17/28
Exemple Multi Materiels Fragment
● Afin de réutiliser les fragments● mise en place d'un listener pour que l'activité soit
prévenue du click sur le bouton de FragmentA● codage d'une méthode de mise à jour dans FragmentB
● L'activité principale● à toujours FragmentA● peut ne pas avoir FragmentB
– cas du téléphone
antislashn.org Android - Les fragments 18 - 20/28
Exemple Multi Materiels Fragment
● FragmentA : fichier layout/fragment_a.xml<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="FragmentA" android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText android:id="@+id/editTextInput" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" >
<requestFocus /> </EditText>
<Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="OK" />
</LinearLayout>
antislashn.org Android - Les fragments 18 - 21/28
Exemple Multi Materiels Fragment
● FragmentA : codepublic class FragmentA extends Fragment {
private OnButtonClickedListener listener;
@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_a, container,false);
Button b = (Button) view.findViewById(R.id.button1);b.setOnClickListener(new OnClickListener() {
public void onClick(View v) {if(listener != null)
listener.onButtonClicked();}
});return view;
}
public void setOnButtonClickedListener(OnButtonClickedListener listener){this.listener = listener;
}
public interface OnButtonClickedListener{void onButtonClicked();
}}
interface à implémenter pour êtreprévenu d'un clic sur le bouton
un clic sur le bouton invoquera l'appelde l'implémentation de l'interface
antislashn.org Android - Les fragments 18 - 22/28
Exemple Multi Materiels Fragment
● FragmentB : fichier layout/fragment_b.xml<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="FragmentB" android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView android:id="@+id/textViewOutput" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="libellé" android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
antislashn.org Android - Les fragments 18 - 23/28
Exemple Multi Materiels Fragment
● FragmentB : code
public class FragmentB extends Fragment {
@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){View view = inflater.inflate(R.layout.fragment_b, container,false);
return view;}
public void update(String value) {TextView tv = (TextView) getActivity().findViewById(R.id.textViewOutput);tv.setText(value);
}}
méthode de mise à jour du champ
antislashn.org Android - Les fragments 18 - 24/28
Exemple Multi Materiels Fragment
● Code de l'activité principalepublic class MainActivity extends Activity implements FragmentA.OnButtonClickedListener{
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); FragmentA a = (FragmentA) getFragmentManager().findFragmentById(R.id.fragment_a); a.setOnButtonClickedListener(this); }
public void onButtonClicked() {FragmentB b = (FragmentB) getFragmentManager().findFragmentById(R.id.fragment_b);EditText et = (EditText) findViewById(R.id.editTextInput);
if(b==null){Intent intent = new Intent(this, ActivityB.class);intent.putExtra("value",et.getText().toString());startActivity(intent);
} else {b.update(et.getText().toString());
}}
}
implémentation du listener
enregistrement du listener auprès du fragment
recherche du fragment d'affichage
le fragment vaut null si téléphoneune activité qui contient FragmentBest alors lancée
mise à jour de FragmentB si tablette
antislashn.org Android - Les fragments 18 - 25/28
Exemple Multi Materiels Fragment
● ActivityB : code
public class ActivityB extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_b); Intent intent = getIntent(); String value = intent.getExtras().getString("value"); FragmentB b = (FragmentB) getFragmentManager().findFragmentById(R.id.fragment_b); b.update(value); }}
récupération de la valeur à afficher
mise à jour du fragment
antislashn.org Android - Les fragments 18 - 26/28
Cycle de vie
ajout dufragment
onAttach() onCreate() onCreateView()
onActivityCreated() onStart() onResume()
le fragmentest actif
onPause()
retour en arrièresuppression/déplacement
onStop() onDestroyView() le fragment est mis dans lavue depuis la pile
onDestroy()onDetach()le fragmentest détruit
antislashn.org Android - Les fragments 18 - 28/28
Classes Fragment
● Fragment● classe de base du fragment
● DialogFragment● affichage d'une boîte de dialogue
● ListFragment : ● affichage d'une liste d'éléments● utilise un adaptateur, comme ListActivity
● PreferenceFragment ● affiche les préférences● similaire à PreferenceActivity
antislashn.org Android - Graphisme 19 - 2/25
Applications graphiques
● Android offre plusieurs approches pour gérer les applications graphiques● dessiner dans un Canvas● dessiner dans une View
– si l'application ne nécessite une mise à jour importante de l'affichage (frame-rate speed)
● créer des objets de type Drawable● utiliser l'accélération matérielle
– depuis Android 3.0● utiliser OpenGL
antislashn.org Android - Graphisme 19 - 3/25
Utiliser une View
● Créer une classe dérivée de View● ajouter cette classe dans un layout.xml● la classe est alors prise en charge par le système● sous Eclipse la classe de type View apparaît dans
"Custom & Library Views"
antislashn.org Android - Graphisme 19 - 4/25
Utiliser une View
● La méthode onDraw(Canvas canvas) de la View est invoquée lorsque le dessin de la vue est requis● par le système● par programmation si appel de la méthode invalidate()
● Le Canvas reçu correspond à la zone d'affichage du View● peut correspondre à l'écran entier
antislashn.org Android - Graphisme 19 - 5/25
Opérations graphiques de base
● La classe Paint permet de positionner les attributs utilisés pour dessiner● définition de couleur
– setARGB(int alapha, int r, int g, int b)
– setColor(int color)
● définition de la taille d'un point– setStokeWidth(float width)
● anti-aliasing– setAntiAlias(boolean aa)
– isAntiAlias(boolean a)
● style de bordure– setStyle(Style style)
antislashn.org Android - Graphisme 19 - 6/25
Opérations graphiques de base
● Les opérations graphiques de base sont effectuées sur la classe Canvas● connaître les dimensions : getWidth(),getHeight()● couleur de fond : drawRGB(int r, int g, int b)● dessiner un pixel :
– drawPoint(float x, float y, Paint p)
● dessiner une ligne : – drawLine(float x1, float y1, float x2, float y2, Paint p)
● de manière générale... dessiner une forme– drawRect(...), drawRoundRect(...), drawCircle(...), etc
antislashn.org Android - Graphisme 19 - 7/25
Opérations graphiques de base
● Extrait du projet "Terrain view"public class Terrain extends View {
public Terrain(Context context) {super(context);
}
public Terrain(Context context, AttributeSet attrs) {super(context, attrs);
}
public Terrain(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);
}
@Override public void onDraw(Canvas canvas) {
canvas.drawRGB(255, 255, 255);Paint pCercle = new Paint();Paint pTrait = new Paint();pCercle.setARGB(255, 255, 0, 0);pTrait.setARGB(255, 0, 0, 0);canvas.drawLine(0, 0, this.getWidth(), this.getHeight(), pTrait);canvas.drawLine(this.getWidth(), 0, 0, this.getHeight(), pTrait);canvas.drawCircle(this.getWidth()/2,this.getHeight()/2, 10, pCercle);
}}
taille du View
antislashn.org Android - Graphisme 19 - 8/25
Les bitmaps
● Il est possible d'utiliser des bitmaps au format PNG, GIF et JPEG● gestion par la classe Bitmap
● Les fichiers sont en général mis en place dans le répertoire assets
● Les étapes principales sont● chargement du fichier● précision si nécessaire du format de sortie
– Bitmap.Config
● Il est aussi possible de créer un Bitmap vide et de le décorer avec un Canvas pour pouvoir dessiner
antislashn.org Android - Graphisme 19 - 9/25
Les bitmaps● Extrait du projet "Bitmap"
...@Overridepublic void onDraw(Canvas canvas) {
canvas.drawRGB(255, 255, 255);Random rand = new Random();int x1, y1, x2, y2;x1 = rand.nextInt(this.getWidth());y1 = rand.nextInt(this.getHeight());x2 = x1 + bitmap.getWidth();y2 = y1 + bitmap.getHeight();rectangle.set(x1, y1, x2, y2);canvas.drawBitmap(bitmap, null, rectangle, null);
}
private void initBitMap() {rectangle = new Rect();InputStream in = null;try {
AssetManager assetManager = this.getContext().getAssets();in = assetManager.open("android.jpg");bitmap = BitmapFactory.decodeStream(in);Log.d(this.getClass().getCanonicalName(),">>> format de l'image : "+bitmap.getConfig());
} catch (Exception e) {Log.e(this.getClass().getCanonicalName(), ">>>> ERROR <<<<<", e);} finally{
...}
}...
antislashn.org Android - Graphisme 19 - 10/25
Les polices de caractères
● Les fichiers TTF (True Type Fonts) peuvent être utilisés via la classe Typeface● chargement du fichier par
– la méthode statique createFromAssets(...) qui charge un fichier depuis le répertoire assets
– la méthode statique createFomFile(...) qui charge un fichier depuis un répertoire quelconque
● Les attributs des polices sont définis via la classe Paint● couleur, taille, alignement, décoration, …
● La méthode drawText(...) du Canvas affiche le texte
antislashn.org Android - Graphisme 19 - 11/25
Les polices de caractères
● Extrait du projet "Font"public void onDraw(Canvas canvas) {
canvas.drawRGB(255, 255, 255);Typeface tf = Typeface.createFromAsset(this.getContext().getAssets(), "times.ttf");Paint ptf = new Paint();ptf.setTypeface(tf);ptf.setARGB(255, 0, 0, 255);ptf.setTextSize(25);float inclinaison = (float) 0.25;ptf.setTextSkewX(inclinaison);canvas.drawText("hello, world", 50, 50, ptf);
}
antislashn.org Android - Graphisme 19 - 12/25
Animation 2D
● L'animation 2D requiert des traitements plus importants que le dessin● calculs réguliers des positions
– gestion des collisions des vaisseaux avec les missiles– affichage des scores– etc.
● Tout ceci est consommateur de temps et ne devrait pas être effectué dans le thread de l'IHM
antislashn.org Android - Graphisme 19 - 13/25
● Solutions possibles● utiliser Thread.sleep(...) dans le thread principal
– on peut mieux faire● créer un thread secondaire
– mais la gestion de l'écran (retournement) doit passer par le thread principal
● notre activité sera relancée
– alors le thread secondaire informe le thread principal lorsque les nouveaux affichages doivent être effectués
– principal défaut : le thread principal gère les objets graphiques
● utiliser une SurfaceView– permet de généré un contenu qui sera ensuite affiché– permet d'utiliser les accélérations matérielles
Animation 2D
antislashn.org Android - Graphisme 19 - 14/25
Animation 2D
● SurfaceView● permet d'accéder à une Surface
– la Surface est utilisée par le "screen compositor" pour créer la vue à l'écran
– lecture des pixels de la Surface et envoie vers le GPU
● peut tourner dans un thread indépendant du thread IHM● SurfaceHolder
● renvoie une SurfaceView● possède une interface SurfaceHolder.Callback
qui permet de répondre aux changements structuraux de la Surface
antislashn.org Android - Graphisme 19 - 15/25
Animation 2D
● Étapes de création d'une animation1.créer son SurfaceView2.créer les objets graphique que le SurfaceView doit
gérer3.coder le comportement des objets graphiques dans la
méthode run()4.coder la gestion du thread
● Cf le projet "Animation2D 01"
antislashn.org Android - Graphisme 19 - 16/25
Animation 2D – étape 1
● Création d'une classe de type SurfaceView● cette classe implémente l'interface Runnable pour le
second thread
public class MonSurfaceViewRunnable extends SurfaceView implements Runnable {
public MonSurfaceViewRunnable(Context context) {super(context);
}
public MonSurfaceViewRunnable(Context context, AttributeSet attrs) {super(context, attrs);
}
public MonSurfaceViewRunnable(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);
}
public void run() {
}}
antislashn.org Android - Graphisme 19 - 17/25
Animation 2D – étape 2
● Création des objets graphiques● dans la classe MonSurfaceviewRunnable
– la méthode init() sera appelée dans tous les constructeurs
private Thread threadAnim;private Balle balle;private SurfaceHolder sh;
private void init(){balle = new Balle(100,100,10,this.getWidth(),this.getHeight());sh = this.getHolder();
}
récupération d'un SurfaceHolder
antislashn.org Android - Graphisme 19 - 18/25
Animation 2D – étape 3
● Codage du comportement des objets dans la méthode run()
public void run() {while(true){
if(sh.getSurface().isValid()){Canvas canvas = sh.lockCanvas();canvas.drawRGB(255, 255, 255);Paint paint = new Paint();paint.setAntiAlias(true);paint.setARGB(255, 0, 0, 255);balle.newXY();canvas.drawCircle(balle.x, balle.y, balle.radius, paint);sh.unlockCanvasAndPost(canvas);try {
Thread.sleep(1000);} catch (InterruptedException e) {
Log.e(MonSurfaceViewRunnable.class.getCanonicalName(),">>> ERROR <<<",e);}
}}
}
vérification de la validité de la Surface
verrouillage de la Surface pour écriture
déverrouillage de la Surface, ce quiprovoque l'affichage
antislashn.org Android - Graphisme 19 - 19/25
Animation 2D – étape 4
● Gestion du Thread● il faut synchroniser le Thread avec l'activité
– création des méthodes onResume() et onPause() qui seront appelées par les méthodes du même nom de l'activité
public void onResume(){this.threadAnim = new Thread(this);this.threadAnim.start();
}
public void onPause(){this.threadAnim.interrupt();
}
appelé par onResume() de l'activité
appelé par onPause() de l'activité
antislashn.org Android - Graphisme 19 - 20/25
Animation 2D – étape 4
● Code de l'activité
public class Animation01Activity extends Activity { private MonSurfaceViewRunnable monView ; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); monView = (MonSurfaceViewRunnable) findViewById(R.id.monSurfaceViewRunnable1); } @Override public void onResume(){ super.onResume(); monView.onResume(); } @Override public void onPause(){ super.onPause(); monView.onPause(); }}
antislashn.org Android - Graphisme 19 - 21/25
Animation 2D
● Utiliser les événements pour interagir avec les graphiques● événements de la classe View
– onKeyDown(...)– onKeyUp(...)– onTrackBallEvent(...)– onTouchEvent(...)
● ces méthodes doivent renvoyer un booléen● exemple slide suivant
antislashn.org Android - Graphisme 19 - 22/25
Animation 2D● Extrait du projet "Suivi"
public class Terrain extends View{private Balle balle;
...
@Override public void onDraw(Canvas canvas) {
canvas.drawRGB(255, 255, 255);if(balle!=null){
Paint pCercle = new Paint();pCercle.setARGB(255, 255, 0, 0);canvas.drawCircle(balle.x,balle.y, balle.radius, pCercle);
}}Overridepublic boolean onTouchEvent(MotionEvent event){
if(balle!=null){int l = balle.x - balle.radius-10;int t = balle.y - balle.radius-10;int r = balle.x + balle.radius+10;int b = balle.y + balle.radius+10;balle.x = (int) event.getX();balle.y = (int) event.getY();invalidate(l,t,r,b);
}return true;
}...
on invalide que la zone à re-desssinerce qui provoque l'appel de onDraw(...)
antislashn.org Android - Graphisme 19 - 23/25
Quelques astuces
La classe PowerManager.WakeLock gère le blocage des modes d'économie d'énergie de l'écran● mise en veille, brillance de l'écran● nécessite la permission :
– android.permission.WAKE_LOCK● acquisition d'un verrou auprès du service PowerManager
● le verrou doit être géré dans le onPause et onResume
antislashn.org Android - Graphisme 19 - 24/25
Quelques astuces
● Extrait du projet "WakeLock"public class WakeLockActivity extends Activity {private WakeLock wakeLock;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK,
this.getClass().getCanonicalName()); } @Override public void onPause(){ wakeLock.release(); } @Override public void onResume(){ wakeLock.acquire(); }}
antislashn.org Android - Graphisme 19 - 25/25
Quelques astuces
● La classe WindowManager.LayoutParams permet de gérer les caractéristiques de l'écran● dont la brillance● ici un exemple de passage mode plein écran
– setFlag(int flags, int mask)
public class FullScreenActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.main); }}
enlève la barre de titre del'application
la barre de notification est cachée
antislashn.org Android - Gestion des équipements 20 - 2/12
Les équipements
● Les téléphones et tablettes intègrent des équipements divers● caméra, appareil photo, carte son, écran● capteurs divers
– gyroscope, gps, boussole, détecteur de lumière, …
● Les équipements ne sont pas tous présents sur tous les matériels
● La liste des équipements supportés évolue avec les niveaux d'API
antislashn.org Android - Gestion des équipements 20 - 3/12
Les capteurs
● Les capteurs sont catégorisés en● capteurs de déplacement
– accéléromètre, gravité, gyroscope, accélération linéaire et vectorielle
● capteurs de position– champ magnétique, orientation, proximité
● capteurs environnementaux– température, luminosité, pression barométrique, humidité
● En fonction des choix de construction certains capteurs peuvent renvoyer des résultat binaire ou discrets● exemple : capteur de proximité (près/loin ou distance)
antislashn.org Android - Gestion des équipements 20 - 4/12
Les capteurs
● Capteurs disponibles en fonction des versions
antislashn.org Android - Gestion des équipements 20 - 5/12
Les capteurs
● L'accès aux capteurs passe par la classe SensorManager
● La classe Sensor représente un capteur● Pour recevoir les données d'un capteur il faut
● enregistrer le capteur auprès du framework de gestion des capteurs– le retirer lors de l'arrêt de l'application
● implémenter l'interface SensorEventListener– méthodes onAccuranceChanged et onSensorChanged
SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
antislashn.org Android - Gestion des équipements 20 - 6/12
Les capteurs
● Types de capteur● constantes de la classe Sensor
antislashn.org Android - Gestion des équipements 20 - 7/12
Les capteurs
● Exemple de récupération de la liste des capteurs● voir suite page suivante
public class SensorListActivity extends Activity {
private static Sensor sensor;private static SensorManager sm;private static final String tag = SensorListActivity.class.getCanonicalName();
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(tag,">>>> onCreate <<<<"); setContentView(R.layout.activity_sensor_list); sm = (SensorManager) getSystemService(SENSOR_SERVICE); logSensorList(); } ... }
antislashn.org Android - Gestion des équipements 20 - 8/12
Les capteurs
● Exemple de récupération de la liste des capteurs... private void logSensorList(){
List<Sensor> sensors; String type; sensors = sm.getSensorList(Sensor.TYPE_ALL); if(sensors.size() == 0) { Log.d(tag,"Aucun équipement détecté"); return; } for(Sensor sensor : sensors){ switch(sensor.getType()){ case Sensor.TYPE_ACCELEROMETER: type =" ACCELEROMETRE"; break; ...
default:type = "NON REPERTORIE"; break;
} Log.d(tag," >>> " + type + " : " + sensor.getName()+" - maximum range : "
+sensor.getMaximumRange()+" - resolution : "+sensor.getResolution()); }}...
antislashn.org Android - Gestion des équipements 20 - 9/12
Les données d'un capteur
● Les données d'un capteur sont encapsulées dans l'événement SensorEvent passé à la méthode onSensorChanged du listener● propriété values de l'événement
● Le tableau des données values à un nombre d'éléments différents● cf. la javadoc de SensorEvent● l'unité est précisée dans la documentation
antislashn.org Android - Gestion des équipements 20 - 10/12
Lecture des données d'un capteur
● Lecture de la luminosité● suite page suivante
public class LightSensorActivity extends Activity implements SensorEventListener{
private static SensorManager sensorManager;private static Sensor sensor;private static final String tag = LightSensorActivity.class.getCanonicalName();
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_light_sensor); sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); } @Override protected void onResume(){ super.onResume(); sensorManager.registerListener(this, sensor,SensorManager.SENSOR_DELAY_FASTEST); }
... enregistrement du listenerauprès du framework
récupération du SensorManager
récupération du capteur de luminosité
antislashn.org Android - Gestion des équipements 20 - 11/12
Lecture des données d'un capteur
● Lecture de la luminosité● suite
... @Override protected void onStop(){ super.onStop(); sensorManager.unregisterListener(this); }
public void onAccuracyChanged(Sensor sensor, int accuracy) {Log.d(tag,"=> changement de précision sur "+sensor.getName()+" = "+accuracy);
}
public void onSensorChanged(SensorEvent event) {Log.d(tag,">>> valeur = "+event.values[0]+" Lux (précision : "+event.accuracy+")");
} }
désinscription du listenerauprès du framework
récupération de la luminosité en Lux
antislashn.org Android - Gestion des équipements 20 - 12/12
L'écran tactile
● Les interactions avec l'écran tactile peuvent être suivies via● la surcharge, dans l'activité, de la méthode
– public boolean onTouchEvent(MotionEvent event)
● l'implémentation du listener View.OnTouchListener– public boolean onTouch(View view, MotionEvent event)
● L'événement MotionEvent permet de connaître● le type d'action qui a été effectuée
– ACTION_MOVE, ACTION_DOWN, …
● les coordonnées de l'appui● la pression, la taille, l'orientation, ...
antislashn.org Android - Géolocalisation et Google Map 2/22
Géolocalisation
● Unités des coordonnées géographiques● DMS : degrés°minute'seconde"
– 49°41'55" ou en plus précis 49°41'55.11"● DM : degrès°minute décimale'
– 49°41.91'● DD : degrès décimal
– 49.6985°
source : Wikipedia Commons
antislashn.org Android - Géolocalisation et Google Map 3/22
Géolocalisation
● Latitude (lat.)● positionnement nord-sud d'un point sur la terre
– mesure angulaire de 0° à l'équateur jusqu'à 90° aux pôles
source : Wikipedia Commons
antislashn.org Android - Géolocalisation et Google Map 4/22
Géolocalisation
● Longitude (long. ou lg.)● positionnement est-ouest d'un point sur la terre
– 360 méridiens● cercles imaginaires tracés sur le globe reliant les pôles
géographiques, séparés par un degrés d'arc
– méridien de référence : Greenwich– mesure de 180° ouest à 180° est par rapport à Greenwich
source : Wikipedia Commons
antislashn.org Android - Géolocalisation et Google Map 5/22
Géolocalisation
● Standards d'échange de positions vers l'émulateur● trame NMEA 0183
– commande de l'émulateur : geo nmea– spécification de communication entre équipement maritimes
● GPS, systèmes de cartographie, alarmes, pilotes automatiques, …
– trames supportées● $GPGGA pour GPS Fix et Date
– date et heure, longitude, latitude, élévation● $GPRCM utilisé pour la navigation
– date et heure, longitude, latitude, vitesse, route sur le fond● trame GPS Fix
– commande émulateur : geo fix● point GPS simple : lat. et Long. en degrés décimal, élévation en option
antislashn.org Android - Géolocalisation et Google Map 6/22
Géolocalisation
● Le service de géolocalisation utilise différents moyens● relais opérateurs, wifi, GPS● les moyens techniques étant plus ou moins précis
● Le service de géolocalisation utilise la classe LocationManager● l'instance de LocationManager est récupérée via getSystemService(...)
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
antislashn.org Android - Géolocalisation et Google Map 7/22
Géolocalisation
● L'utilisation de la géolocalisation nécessite des permissions qui sont précisées dans le fichier manifeste
● Le suivi de la position est mis en place par l'implémentation du listener LocationListener● méthode onLocationChanged(Location location)● Location encapsule les données comme la longitude,
la latitude, la vitesse, ...
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
antislashn.org Android - Géolocalisation et Google Map 8/22
Geolocalisation
● La classe Geocoder permet de passer● d'une coordonnée connue à une adresse
– getFromLocation(...)
● d'une adresse à une coordonnée– getFromLocationName(...)
● dans tous les cas on récupère une liste d'Address● Nécessite la présence du réseau
● tester la méthode isPresent() pour connaître la disponibilité de l'implémentation
antislashn.org Android - Géolocalisation et Google Map 9/22
Google Map
● Le service de géolocalisation est souvent utilisé en liaison avec Google Map
● Pour pouvoir utiliser Google Map● utiliser une Google API
– choisir une Google API au lieu d'une Android API lors de la mise en place de projet
– si le projet est déjà en place changer l'API dans les propriétés du projet
– attention la documentation se trouve dans les add-ons● utiliser une clé délivrée par Google
– cette clé est unique par rapport à la signature SHA1 de la clé du certificat des applications
● en mode debug, il s'agit du fichier debug.keystore
antislashn.org Android - Géolocalisation et Google Map 10/22
GoogleMap
● Avant tout il faut activer le service Google Map● https://code.google.com/apis/console● vous devez possédez un compte Google
antislashn.org Android - Géolocalisation et Google Map 11/22
Google Map● Récupération de l'empreinte MD5
● voir où ce trouve le fichier debug.keystore sur votre système– sous Windows : C:\Users\xxxxx\.android\debug.keytsore– sous Linux : ~/.android/debug.keystore
● utiliser l'outils keytool du JDK– dans le répertoire bin du JDK
● lancer en ligne de commande :– keytool -list -v -keystore <chemin .android>/debug.keystore
● mots de passe : android
antislashn.org Android - Géolocalisation et Google Map 12/22
Google Map
● Aller dans la console "Google APIs Console" : ● https://code.google.com/apis/console/
● Puis dans "API Access"
● et demander la création d'un certificat pour Android
antislashn.org Android - Géolocalisation et Google Map 13/22
Google Map
● Pour la création de la clé il vous faut● l'empreinte SHA1● le package de l'application
antislashn.org Android - Géolocalisation et Google Map 14/22
Google Map
● Récupérer la clé● cette clé sera insérée dans le fichier layout qui inclura le MapView
antislashn.org Android - Géolocalisation et Google Map 15/22
Google Map
● La version actuelle de Google Map nécessite l'utilisation de la librairie "google play services"● installation par le "Android SDK Manager"
– dans la section "Extras"– l'installation sera effectuée dans le répertoire
● <repertoire-sdk>/extras/google/google_play_services
antislashn.org Android - Géolocalisation et Google Map 16/22
Google Map
● google-play-services_lib est livré sous forme de librairie
● Il faut importer le projet dans le workspace● File → Import → Existing Android Code Into Workspace
● Les projets utilisant Google Map devront référencer cette librairie
antislashn.org Android - Géolocalisation et Google Map 17/22
Projet Google Map
● Créez un projet Android● Dans le fichier Android.Manifest.xml ajouter les
permissions suivantes
...<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />...
antislashn.org Android - Géolocalisation et Google Map 18/22
Projet Google Map
● Toujours dans le fichier AndroidManifest.xml, ajouter les <meta-data> suivantes● juste avant balise de fermeture </application>
...<meta-data
android:name="com.google.android.gms.version"android:value="@integer/google_play_services_version" />
<meta-dataandroid:name="com.google.android.maps.v2.API_KEY"android:value="AIzaSyBm6efguTn6CwfcTZSNh0LXUJ9nFYI7o3Q" />
</application>...
clé d'utilisation de l'API
antislashn.org Android - Géolocalisation et Google Map 19/22
Projet Google Map
● Le projet doit référencer le projet google-play-services● clic droit sur le projet puis Properties
antislashn.org Android - Géolocalisation et Google Map 20/22
Projet Google Map
● Référencement de la librairie google-play-services
antislashn.org Android - Géolocalisation et Google Map 21/22
Projet Google Map
● Ajoutez dans le layout le widget de Google Map
... <fragment android:id="@+id/map" android:name="com.google.android.gms.maps.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent"/>..
antislashn.org Android - Géolocalisation et Google Map 22/22
Projet Google Map
● Utilisation du Map● exemple simple qui centre la carte sur une coordonnéepublic class MapActivity extends Activity {
static final double lng = 2.6611;static final double lat = 49.7008;private GoogleMap map;
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.main);map = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();
changeView();}
private void changeView(EditText etlat, EditText etlng) {LatLng latLng = new LatLng(lat), Double.parseDouble(lng);map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
}
}
Top Related