528
Développement pour Android version support : 1.9

Développement Android

Embed Size (px)

DESCRIPTION

Support de formation pour les développeurs. Pour les formations, ce support est complété par un livret d'exercices pour les stagiaires et de l'ensemble de tous les exemples, sous forme de projets Eclipse.

Citation preview

Développement pour Android

version support : 1.9

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 - 2/15

Matériels sous Android

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 - 6/15

Présentation de la plateforme

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 - 1/48

Outils de développement

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 - 1/20

ApplicationHello, world

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 - 1/56

Composants graphiquesde base

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 - 7/56

Les écrans Android

source : Google

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 - 1/28

Intent

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 - 1/22

Les activitésActivity

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 - 8/22

Activity

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 - 1/29

Composant ListView

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- 1/33

Autres composants graphiques

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 - 1/13

Les menus

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 - 1/36

La persistance des données

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 - 1/33

Les services

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 - 31/33

Service – exposition par AIDL

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 - 1/11

Réception d'événements avecBroadcastReceiver

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 - 1/12

Processus et threads

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 - 1/15

Application Widget

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 - 1/28

Les fragments

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 - 18/28

Exemple Multi Materiels Fragment

antislashn.org Android - Les fragments 18 - 19/28

Exemple Multi Materiels Fragment

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 - 27/28

Cycle de vie

source : Google

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 - 1/25

Graphisme

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 - 1/12

Gestion des équipements

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 1/22

GéolocalisationGoogle Map

version : 2.0

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));

}

}