David Defour - Université de Perpignan
David Defour - Université de Perpignan
David Defour - Université de Perpignan
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
jeudi 26 janvier 12<br />
PROGRAMMATION SOUS<br />
ANDROID<br />
<strong>David</strong> <strong>Defour</strong><br />
<strong>Université</strong> <strong>de</strong> <strong>Perpignan</strong><br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/
• Equipements<br />
• Salle machine avec:<br />
ORGANISATIONS<br />
• 2 tablettes ACER Iconia A500 sous Android 3.2 (Honeycomb)<br />
• 2 tablettes Archos Internet Tablet 70 sous Android 2.2 (Froyo)<br />
• Au sujet <strong>de</strong> ce module<br />
• 9h <strong>de</strong> CM (6 x 1h 30)<br />
• 21h <strong>de</strong> TDO (7 x 3h)<br />
• Note pour l’UE : Projet final + soutenance<br />
• Terminologie<br />
jeudi 26 janvier 12<br />
A vos Machines
jeudi 26 janvier 12<br />
DESCRIPTION DU PROJET
• Honnêteté intellectuelle<br />
RECOMMANDATIONS<br />
• Toutes parties <strong>de</strong> co<strong>de</strong>, texte, algorithmes, ... qui n’est pas <strong>de</strong> vous et dont la référence n’est pas clairement<br />
indiquée conduira à un ZERO<br />
• Commentaires<br />
• Le programme <strong>de</strong>vra être clairement structuré (décrit dans le rapport) et commenté (utilisation <strong>de</strong><br />
javadoc et d’éclipse)<br />
• Délai<br />
• Le projet <strong>de</strong>vra impérativement être rendu avant le 31 mars 2012<br />
• Sujets<br />
jeudi 26 janvier 12<br />
• Un sujet vous est proposé par défaut,<br />
• En accord avec le responsable du cours il est possible <strong>de</strong> proposer un autre sujet avant le 15 février 2012
DESCRIPTION<br />
• Titre : Réalisation d’une interface en drag-&-drop d’un<br />
interpréteur <strong>de</strong> langage Logo sur le modèle <strong>de</strong> App Inventors<br />
• Objectifs<br />
jeudi 26 janvier 12<br />
• Rendre possible la programmation sur un périphérique<br />
Android<br />
• Programmer sans clavier<br />
(Attention: c’est une condition importante dans ce projet, il<br />
faut minimiser son usage)
DESCRIPTION DE L’INTERFACE<br />
• Fenêtre d’édition divisée en 2 parties<br />
• Une boite à objet avec <strong>de</strong>s boites symbolisant les briques <strong>de</strong> base du langage pour<br />
faire bouger la tortue<br />
• Une zone <strong>de</strong> programmation<br />
• Un interpréteur <strong>de</strong> votre langage pour visualiser le résultat<br />
• Fonctionnalités supplémentaires<br />
jeudi 26 janvier 12<br />
• Bouton «save», «load», «do», «undo», «<strong>de</strong>bug», «help», «procédures», «copy/paste»<br />
• Gestion <strong>de</strong>s erreurs
jeudi 26 janvier 12<br />
EXAMPLE: APP INVENTOR
• Déplacements<br />
• Gestion du trait<br />
STRUCTURATION DU<br />
• Gestion du contrôle<br />
jeudi 26 janvier 12<br />
LANGAGE
jeudi 26 janvier 12<br />
DÉPLACEMENTS<br />
Ordre Fonctions<br />
AV n Comman<strong>de</strong> à la tortue d’avancer <strong>de</strong> n pas<br />
TD n Comman<strong>de</strong> à la tortue d’effectuer une rotation <strong>de</strong> n <strong>de</strong>grés à droite<br />
TG n Comman<strong>de</strong> à la tortue d’effectuer une rotation <strong>de</strong> n <strong>de</strong>grés à gauche<br />
REC n Comman<strong>de</strong> à la tortue <strong>de</strong> reculer <strong>de</strong> n pas<br />
FPOS [n1 n2] Place la tortue à la position (n1,n2) <strong>de</strong> l’écran<br />
FCAP n Fixe le cap <strong>de</strong> la tortue
jeudi 26 janvier 12<br />
GESTION DU TRAIT<br />
Ordre Fonctions<br />
VE Efface l’écran<br />
MT Rend la tortue visible<br />
CT Rend la tortue invisible à l’utilisateur<br />
LC Deman<strong>de</strong> à la tortue <strong>de</strong> lever le crayon<br />
BC Deman<strong>de</strong> à la tortue <strong>de</strong> baisser le crayon<br />
FCC n Fixe la couleur du crayon <strong>de</strong> la tortue
GESTION DU CONTRÔLE<br />
Ordre Fonctions<br />
REPETE n [ liste ] Répète n fois les instructions contenues dans la liste<br />
HASARD n Renvoie un nombre compris entre 0 et n<br />
CAP Renvoie le cap <strong>de</strong> la tortue<br />
LOOP Renvoie le nombre <strong>de</strong> fois que l’instruction REPETE a été exécutée<br />
SI predicat<br />
[ liste 1] [ liste2 ]<br />
Si prédicat est vrai, exécute les instructions <strong>de</strong> liste1 sinon celles <strong>de</strong> liste2. La liste 2 est optionnelle.<br />
TANQUE exp [liste] Répète les instructions contenues dans liste tant que exp est vrai.<br />
jeudi 26 janvier 12
LANGAGE, FONCTIONNALITÉS<br />
• BONUS :<br />
jeudi 26 janvier 12<br />
• Gestions <strong>de</strong>s procédures<br />
AVANCÉES
RÉFÉRENCES:<br />
• http://lwh.free.fr/pages/prog/logo/Logo.pdf<br />
• http://www.appinventorbeta.com/learn/reference/in<strong>de</strong>x.html<br />
jeudi 26 janvier 12
PROGRAMMATION ANDROID:<br />
jeudi 26 janvier 12<br />
PRÉSENTATION<br />
<strong>David</strong> <strong>Defour</strong><br />
<strong>Université</strong> <strong>de</strong> <strong>Perpignan</strong><br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/
• Motivations<br />
RÉSUMÉ DU COURS<br />
• Web Apps vs. Mobile Apps<br />
• iPhone Apps vs. Android Apps<br />
• Livres & Références<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
WEB APPS VS.<br />
ANDROID APPS
AVANTAGES DES APPLI WEB<br />
• Accès universel<br />
• Navigateurs présent partout<br />
• N’importe quel périphérique connecté<br />
peu accé<strong>de</strong>r à du contenu<br />
• PCs, Macs, Linux, Android,<br />
iPhone, Blackberry, etc.<br />
• Mise à jour automatique<br />
• Le contenu vient du serveur =><br />
toujours à jour<br />
• Outils et métho<strong>de</strong>s éprouvées<br />
• Plusieurs langages<br />
• Java, PHP, .NET, Ruby/Rails, CGI, etc.<br />
jeudi 26 janvier 12
INCONVÉNIENTS DES APPLI<br />
WEB<br />
• Peu d’Interface HM avec peu <strong>de</strong> contrôle<br />
• Textfield, text area, button, checkbox, radio, list box, combo box. c’est tout ! Pas <strong>de</strong><br />
<strong>de</strong>ssin direct (Sauf pour les canvas en HTML5)<br />
• Ne peut pas interagir avec les ressources locales<br />
• Impossibilité <strong>de</strong> lire <strong>de</strong>s fichiers, d’appeler <strong>de</strong>s programmes ou d’accé<strong>de</strong>r aux<br />
périphériques <strong>de</strong> la machine<br />
• Communication inefficace<br />
• HTTP est un protocole faible<br />
• Difficulté d’écrite<br />
• Nécessite <strong>de</strong>s connaissances en plusieurs techno<br />
• Java, HTML, HTTP, CSS, JavaScript, XML<br />
• Conçu pour <strong>de</strong>s périphériques avec <strong>de</strong> grand écran et une souris<br />
• Plus difficile <strong>de</strong> les utiliser sur un plus petit téléphone avec écran tactile<br />
jeudi 26 janvier 12
AVANTAGES DES APPLI<br />
MOBILES<br />
• Plusieurs interfaces <strong>de</strong> contrôles GUI<br />
• Textfield, text area, button, checkbox, radio, list box, combo box,<br />
clock, calendar, date picker, dialog box, image gallery, etc.<br />
• Comparable à la programmation sur PC<br />
• Supports du <strong>de</strong>ssin direct<br />
• Les jeux animés <strong>de</strong> type Angry Birds sont possibles<br />
• Possibilité d’interagir avec les ressources locales<br />
jeudi 26 janvier 12<br />
• Possibilités <strong>de</strong> lire les fichiers (ex: liste <strong>de</strong> contact), BD locale,<br />
accès au GPS, lancement d’un appel GSM, accès au micro, au<br />
haut-parleur, lecture <strong>de</strong> l’orientation <strong>de</strong> l’écran, etc...
AVANTAGES DES APPS<br />
MOBILES<br />
• Communication efficace<br />
• Possibilité d’utiliser le protocole <strong>de</strong> communication <strong>de</strong> votre choix<br />
• Plus facile à écrire<br />
• Un seul langage à maîtriser<br />
• Java pour Android<br />
• Objective C pour iPhone<br />
• Conçu pour <strong>de</strong>s périphériques avec <strong>de</strong> petit écran tactile<br />
• Les apps et les interfaces GUI sont optimisées pour ce type<br />
d’environnement<br />
jeudi 26 janvier 12
INCONVÉNIENTS DES APPS<br />
• Pas d’accès universel<br />
MOBILES<br />
• Les Apps doivent être installées sur chaque périphérique<br />
• Une apps Android ne fonctionnera pas sur iPhone, Blackberry,<br />
PC, Mac, où box Linux<br />
• Gestion <strong>de</strong>s updates difficile<br />
• L’utilisateur doit intervenir pour installer la <strong>de</strong>rnière version<br />
• Plus récent (esp. Android)<br />
jeudi 26 janvier 12<br />
• Manque <strong>de</strong> standard, d’outils et <strong>de</strong> métho<strong>de</strong>s établits,<br />
• ... mais la programmation Android est proche <strong>de</strong> la<br />
programmation Java classique qui est elle ancienne.
ANDROID<br />
APPS<br />
VS.<br />
IPHONE APPS<br />
jeudi 26 janvier 12
INSTALLATION<br />
• Apps génériques<br />
• Sélection plus importante pour iPhone<br />
• Android essaie <strong>de</strong> se rattraper<br />
• Apps adhoc pour l’entreprise<br />
• Les apps iPhone ne peuvent s’installer que via l’App Store<br />
• Vous <strong>de</strong>vez soumettre votre apps à l’Apple App Store et obtenir leur feu vert, même<br />
pour <strong>de</strong>s applis privées <strong>de</strong>stinées à votre société.<br />
• (sauf si vous JailBreaké votre Iphone)<br />
• Les apps Android peuvent s’installées via :<br />
• Google App Store<br />
• Amazon App Store<br />
• Connexion USB à partir <strong>de</strong> votre PC<br />
• Email<br />
• Votre Site Web<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
LANGUAGES DE PROG<br />
• iPhone<br />
• Objective-C<br />
• Proche du C++, mais pas i<strong>de</strong>ntique<br />
• Android<br />
• Java<br />
• Langage le + utilisé dans le mon<strong>de</strong> <strong>de</strong> l’entreprise<br />
• C/C++<br />
• Possibilité d’appeler<br />
The real reason Android runs Java<br />
nativement (avec<br />
difficulté) via une<br />
approche <strong>de</strong> type JNI<br />
From Randall Munroe and xkcd.com
OS POUR LE<br />
DÉVELOPPEMENT DES APPS<br />
• iPhone<br />
• Macs<br />
• Android<br />
• Tout ce qui peut installer<br />
Java et Eclipse<br />
• Macs<br />
• PCs<br />
• Linux<br />
• Solaris<br />
jeudi 26 janvier 12<br />
From http://www.hongkiat.com/blog/mac-vs-pc-myth-busting-consumer-gui<strong>de</strong>/
jeudi 26 janvier 12<br />
PROGRAMMING JOBS:<br />
ANDROID VS. IPHONE<br />
• Cadre: In<strong>de</strong>ed.com ne montre que la tendance<br />
• Offre d’emploie contenant les 2 mots n’importe où<br />
• Biaisé par le site <strong>de</strong> références
GOOGLE SEARCH: ANDROID<br />
jeudi 26 janvier 12<br />
VS. IPHONE PROGRAMMING<br />
• Cadre: montre la tendance sur les volumes <strong>de</strong> requête<br />
• Example: plus <strong>de</strong> tuto clair pour Android or iPhone implique<br />
moins <strong>de</strong> recherche
GAINS LIÉS À LA PUBLICITÉ:<br />
ANDROID (53%) VS. IPHONE (27%)<br />
jeudi 26 janvier 12<br />
• Cadre: la pub ne correspond pas aux volumes, biaisé par les<br />
partenaires <strong>de</strong> Millennial Media
jeudi 26 janvier 12<br />
PRÉSENCE SUR LE MARCHÉ<br />
Cadre: basé sur une étu<strong>de</strong> et non sur <strong>de</strong>s volumes <strong>de</strong> vente réel.<br />
Raw data at http://www.comscore.com/Press_Events/Press_Releases/2011/7/comScore_Reports_May_2011_U.S._Mobile_Subscriber_Market_Share
IPHONE VS. ANDROID<br />
• Lequel utiliser personnellement<br />
• iPhone a plus <strong>de</strong> part <strong>de</strong> marché, un catalogue plus étoffé et<br />
<strong>de</strong>s utilisateurs plus loyaux<br />
• Android est plus ouvert et croit plus rapi<strong>de</strong>ment<br />
• Conclusion: pas <strong>de</strong> vainqueur clair, à vous <strong>de</strong> voir<br />
• Lequel choisir si vous avez <strong>de</strong>s apps maisons<br />
jeudi 26 janvier 12<br />
• Plus difficile avec l’iPhone qu’avec Android.<br />
• iPhone utilise Objective C et Android Java<br />
• Conclusion: Android est le vainqueur
jeudi 26 janvier 12<br />
CONCLUSION<br />
Présentation
RÉFÉRENCES<br />
• Livres (Par ordre <strong>de</strong> préférence)<br />
• Android Developer’s Cookbook (Steele & To)<br />
• Busy Co<strong>de</strong>r’s Gui<strong>de</strong> to Android Development (Murphy)<br />
• En ligne seulement: http://commonsware.com/Android/<br />
• Android in Action, 2 nd Edition (Ableson, Sen, & King)<br />
• Android Application Development for Dummies (Felker)<br />
• Site web:<br />
• http://<strong>de</strong>veloper.android.com/<br />
• De loin la source la plus importante<br />
• Forum Android sur StackOverflow<br />
• http://stackoverflow.com/questions/tagged/android<br />
• La galerie <strong>de</strong>s widget Android<br />
• http://www.droiddraw.org/widgetgui<strong>de</strong>.html<br />
jeudi 26 janvier 12
• Web apps vs. Android apps<br />
jeudi 26 janvier 12<br />
RÉSUMÉ<br />
• Les apps Web fonctionnent sur n’importe quel <strong>de</strong>vice mais<br />
ont une interface GUI faible, ne peuvent utiliser <strong>de</strong><br />
ressources locales (fichiers, BD, GPS, camera) et sont plus<br />
agréable à utiliser avec un grand écran.<br />
• Les apps Android peuvent utiliser les ressources locales, sont<br />
optimisées pour les petits écrans, ont une GUI plus riches,<br />
mais ne peuvent pas être installé sur d’autres type <strong>de</strong> <strong>de</strong>vice.
jeudi 26 janvier 12<br />
QUESTIONS?
jeudi 26 janvier 12<br />
ANDROID: INSTALLATION &<br />
PREMIER DÉMARRAGE<br />
<strong>David</strong> <strong>Defour</strong><br />
<strong>Université</strong> <strong>de</strong> <strong>Perpignan</strong><br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/
RÉSUMÉ DU COURS<br />
• Installation <strong>de</strong>s logiciels et <strong>de</strong> la documentation<br />
• Java<br />
• Eclipse<br />
• Android SDK, base<br />
• Plugin Eclipse ADT<br />
• Mise à jour <strong>de</strong>s composants du SDK<br />
• AVD (Android Virtual Device)<br />
• Lancement d’une application<br />
jeudi 26 janvier 12<br />
• Importer et tester une application existante<br />
L’exécuter sur l’émulateur<br />
• Créer et tester une nouvelle application<br />
L’exécuter sur l’émulateur<br />
• Visualiser les sorties standards dans le DDMS<br />
• Déployer une application sur un périphérique Android connecté en mo<strong>de</strong> USB
jeudi 26 janvier 12<br />
INSTALLATION DE LA<br />
DOCUMENTATION ET DES<br />
LOGICIELS
• Présentation<br />
jeudi 26 janvier 12<br />
JDK POUR JAVA SE 6<br />
• Java 6 est la version la plus récente et rapi<strong>de</strong><br />
(Java 5 est supporté par Android mais non-recommandé)<br />
• Pour les PC, Linux :<br />
• http://www.oracle.com/technetwork/java/javase/downloads/<br />
• Télécharger le JDK et pas seulement le JRE<br />
• Télécharger la SE (Standard Edition), pas la EE ou la ME (Micro Edition)<br />
• Pas besoin <strong>de</strong> la version avec l’IDE NetBeans<br />
• Pour MAC<br />
• Rien a faire (java est installé et maintenu automatiquement)
INSTALLATION DE JAVA SE 6<br />
• http://www.oracle.com/technetwork/java/javase/downloads/<br />
Use this version. The “JDK – Java<br />
Development Kit” inclu<strong>de</strong>s compiler for .java<br />
files, whereas the “JRE – Java Runtime<br />
Environment” is only for executing<br />
prebuilt .class files.<br />
jeudi 26 janvier 12<br />
After downloading, run installer and accept all <strong>de</strong>faults.<br />
This tutorial uses Eclipse, so<br />
do not use this link.<br />
As of summer 2011, there is<br />
no NetBeans plugin for<br />
Android <strong>de</strong>velopment. So,<br />
Eclipse is strongly<br />
recommen<strong>de</strong>d even if you<br />
normally use NetBeans for<br />
Java <strong>de</strong>velopment. However,<br />
IntelliJ IDEA has Android<br />
support: see<br />
http://www.jetbrains.com/<br />
i<strong>de</strong>a/features/<br />
google_android.html
• Présentation<br />
ECLIPSE<br />
• Eclipse est un IDE libre, opensource. Supporte Java, HTML, CSS, Javascript, C++, PHP, ...<br />
• Google propose un plugin Eclipse pour l’intégration du SDK Android<br />
• Fonctionnalités<br />
jeudi 26 janvier 12<br />
• Générales<br />
• Vérifie la syntaxe lors <strong>de</strong> la saisie<br />
• Compilation automatique à chaque sauvegar<strong>de</strong><br />
• Factorisation du co<strong>de</strong>, <strong>de</strong>bbugage, templates<br />
• Spécifiques à Android<br />
• Facilite le déploiement d’apps Android vers l’émulateur<br />
• Configuration d’un environnement virtuel<br />
• Drag-&-Drop GUI
INSTALLATION D’ECLIPSE<br />
• http://eclipse.org, puis section “Downloads”<br />
jeudi 26 janvier 12<br />
• Résultats <strong>de</strong><br />
http://eclipse.org/downloads/<br />
• Sélectionner “for Java” où<br />
“for Java EE” (+ apps web)<br />
• Dernière version (3.6 – Helios) recommandée<br />
• Avant <strong>de</strong>rnière version (3.5 – Ganyme<strong>de</strong>) encore supportée<br />
• Versions plus anciennes (3.4 et
LANCER ECLIPSE<br />
• Dezippez le fichier téléchargé (pas d’installeur!)<br />
• Renommez le répertoire “installDir”<br />
• Double clickez sur eclipse.exe<br />
• A partir <strong>de</strong> installDir/bin<br />
• Clickez sur l’icone “Workbench”<br />
• Au prochain démarrage d’éclipse<br />
workbench apparaîtra<br />
automatiquement<br />
• Astuce:<br />
• Pensez à rajouter un raccourcit sur votre Bureau<br />
jeudi 26 janvier 12
ANDROID SDK<br />
• Présentation<br />
• Bibliothèque spécifique à Android<br />
• Compilateur Dalvik (Machine Virtuelle Android)<br />
• Emulateur Android (Pour tester sans périphérique Android)<br />
• Environnement <strong>de</strong> débuggage DDMS<br />
• Documentation<br />
• Installation<br />
• http://<strong>de</strong>veloper.android.com/sdk/installing.html<br />
• Developer’s Gui<strong>de</strong><br />
• http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/<strong>de</strong>veloping/in<strong>de</strong>x.html<br />
• JavaDoc (API Reference)<br />
• http://<strong>de</strong>veloper.android.com/reference/classes.html<br />
• Tutoriels & articles<br />
• http://<strong>de</strong>veloper.android.com/resources/in<strong>de</strong>x.html<br />
jeudi 26 janvier 12<br />
Bookmarkez ces URLs!
INSTALLATION DU SDK<br />
• Téléchargez et lancez l’installeur<br />
• A partir <strong>de</strong> http://<strong>de</strong>veloper.android.com/sdk/<br />
• I’installez dans C:\android-sdk-windows<br />
• Sets up basic SDK, but omits many components<br />
• Instructions détaillées<br />
• http://<strong>de</strong>veloper.android.com/sdk/installing.html<br />
• A faire plus tard<br />
• Après l’installation du plugin eclipse, nous lancerons la mise à jour<br />
du SDK, pour obtenir les composants manquants.<br />
• Plus facile à faire à partir d’eclipse qu’à partir <strong>de</strong> la ligne <strong>de</strong><br />
comman<strong>de</strong>.<br />
jeudi 26 janvier 12
• Présentation<br />
PLUGIN ADT<br />
• ADT (Android Development Tools) fournit plusieurs<br />
fonctionnalitées accessibles directement <strong>de</strong>puis eclipse :<br />
• Intégration entre Eclipse & les outils Android en lignes <strong>de</strong><br />
comman<strong>de</strong>s<br />
• Constructeur GUI en Drag-and-drop<br />
• Plusieurs ajouts pour le <strong>de</strong>v et <strong>de</strong>bug.<br />
• Instructions détaillées:<br />
jeudi 26 janvier 12<br />
• http://<strong>de</strong>veloper.android.com/sdk/eclipse-adt.html
INSTALLATION DE ADT<br />
• Etapes :<br />
• Démarrez Eclipse<br />
• Help � Install New Software …<br />
• Clickez sur “Add” dans le coin en haut à<br />
droite<br />
• Dans «Add Repository», pour le champ<br />
nom entrez «ADT Plugin» et pour le<br />
champ adresse saisissez https://dlssl.google.com/android/eclipse/<br />
• Clickez sur OK, sélectionnez la checkbox<br />
à coté <strong>de</strong> «Developer Tools», suivant,<br />
acceptez la licence et terminez.<br />
• Mettez à jour le plugin ADT<br />
• Help � Check for Updates<br />
jeudi 26 janvier 12
CONFIGURATION DE ADT<br />
• Définissez l’adresse du SDK<br />
• Window � Preferences � Android<br />
• Clickez Browse et indiquez l’endroit où vous avez installez le SDK<br />
• Optionnel: décochez envoyez les stats à Google<br />
• Window � Preferences � Android � Usage Stats<br />
jeudi 26 janvier 12
MISE À JOUR DES<br />
COMPOSANTS DU SDK<br />
• Lancez le SDK manager<br />
• Window � Android SDK & AVD Manager<br />
• Clickez sur “Available packages” à gauche<br />
• Sélectionnez toutes les entrées non-obsolète “Android<br />
Repository” entries<br />
• Sélectionnez la checkbox à côté <strong>de</strong> “Android<br />
Repository”, désélectionnez les entrées obsolètes,<br />
puis “Install Selected”<br />
• Prend un long moment pour s’exécuter<br />
• Instructions détaillées<br />
• http://<strong>de</strong>veloper.android.com/<br />
sdk/adding-components.html<br />
jeudi 26 janvier 12
ANDROID VIRTUAL DEVICES<br />
(AVDS)<br />
• Présentation<br />
• Un AVD (Android Virtual Device) est une configuration d’Emulateur<br />
Android qui vous laisse modéliser votre périphérique en définissant le<br />
hardware et le software présents<br />
• Concept<br />
• Définissez plusieurs AVDs avec différentes API Android pour tester vos apps<br />
avec au moins :<br />
• Une version récente (ex: 3.x ou 2.3.3)<br />
• Une version courante (2.2 as ou 2011)<br />
• Les statistiques d’utilisations <strong>de</strong>s périphériques Android sont disponible à<br />
http://<strong>de</strong>veloper.android.com/resources/dashboard/platform-versions.html<br />
• Instructions détaillées<br />
• http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/<strong>de</strong>veloping/<strong>de</strong>vices/managing-avds.html<br />
jeudi 26 janvier 12
DÉFINITION D’UN AVD<br />
• Création<br />
• Window � Android SDK puis AVD Manager<br />
• Clickez sur “Virtual <strong>de</strong>vices” à gauche. Clickez Ajout, choisissez options. Vous pouvez<br />
créer plusieurs AVDs..<br />
• Options<br />
• Cible (ex: version <strong>de</strong> l’API)<br />
• 3.x 4.x pour tester les tablettes<br />
• 2.3.3 pour tester les téléphones ‘récent’<br />
• 2.2 pour tester sur <strong>de</strong>s générations plus anciennes<br />
• Taille <strong>de</strong> la SD Card<br />
• Pas indispensable <strong>de</strong> le renseigner (ou alors 4 Go)<br />
• Skin<br />
• Choisissez «<strong>de</strong>fault for the target you chose»<br />
jeudi 26 janvier 12
LANCEMENT D’UNE APPS SUR<br />
jeudi 26 janvier 12<br />
L’EMULATEUR
DANS LES GRANDES LIGNES<br />
• Lancement d’une apps<br />
• Bientôt, vous écrirez votre apps et la lancerez, mais pour le moment , on va utiliser<br />
une apps toutes faites.<br />
• Façons <strong>de</strong> lancer une apps:<br />
• Couverte maintenant<br />
• Emulateur Android : Déploiement direct à partir d’Eclipse.<br />
• Lors <strong>de</strong> développement, vous utilisez ce mo<strong>de</strong> pour réaliser vos tests<br />
• Sur un périphérique Android : Déployé à partir d’un PC via le port USB.<br />
• Couverte plus tard dans cette sections<br />
• Sur un périphérique Android : Déployé à partir d’un site Web<br />
• Sur un périphérique Android : Déployé via les email.<br />
• Sur un périphérique Android : Déployé à partir <strong>de</strong> l’Android Market<br />
• Vos propres apps<br />
• Couvert plus tard, c’est la partie amusante !<br />
jeudi 26 janvier 12
LANCEMENT DE HELLOANDROID<br />
DANS L’EMULATEUR<br />
• HelloAndroid<br />
• Apps très simple à déployer et à exécuter<br />
• Téléchargez le projet à partir <strong>de</strong> la section «Getting Started» du tutoriel Android et<br />
importez le dans Eclipse.<br />
• http://www.coreservlets.com/android-tutorial/<br />
• Etapes<br />
• Import<br />
• File � General � Existing Projects…<br />
• Click-D sur ‘project’ à gauche<br />
• Run As � Android Application<br />
• Longue attente pour que l’émulateur s’initialise<br />
• Ne fermez pas l’émulateur lorsque vous avez finit !<br />
jeudi 26 janvier 12<br />
• La prochaine fois, l’apps se chargera plus rapi<strong>de</strong>ment
jeudi 26 janvier 12<br />
HELLOANDROID<br />
Co<strong>de</strong> will be discussed in next tutorial section.
jeudi 26 janvier 12<br />
HELLO ANDROID
CONCEPTS DE BASE<br />
• Concept<br />
• Lorsque vous créez une nouvelle apps, elle a un simple “Hello World” par défault<br />
• Vous pouvez donc créer une apps sans connaître la syntaxe<br />
(que nous verrons lors <strong>de</strong>s prochaines séances)<br />
• Etapes<br />
• File � New � Project � Android � Android Project<br />
• La prochaine fois, vous pourrez faire<br />
File � New � Android Project<br />
• Remplissez les options comme indiqué<br />
• Lancez le projet comme précé<strong>de</strong>mment<br />
• click-D � Run As � Android Application<br />
jeudi 26 janvier 12
DÉFINITION DES OPTIONS<br />
DU PROJETS<br />
• Paramétrage d’un nouveau projet Android<br />
• Project Name<br />
• Nom du projet sous eclipse, suivez votre propre convention.<br />
• Build Target<br />
• Version d’Android que vous souhaitez utiliser. Pour la plupart <strong>de</strong>s téléphone, choisissez 2.2 ce qui est le plus<br />
utilisé dans le mon<strong>de</strong>.<br />
• Application name<br />
• Nom <strong>de</strong> l’apps lisible par l’humain, le titre sera visible sur la barre Android.<br />
• Package name<br />
• L’application sur un <strong>de</strong>vice Android doit avoir un nom <strong>de</strong> paquet unique. Une façon <strong>de</strong> procé<strong>de</strong>r est <strong>de</strong><br />
faire : com.yourCompany.project<br />
• Create Activity<br />
• Le nom <strong>de</strong> la classe java la plus haute<br />
• Min SDK Version<br />
• Numéro qui doit correspondre au Build Target.<br />
Plus <strong>de</strong> détails à http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/appendix/api-levels.html<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
DÉFINITION DES OPTIONS<br />
DU PROJETS<br />
Eclipse project name<br />
Android version that you want to run on<br />
Human-readable app name<br />
Package. Use naming convention to ensure uniqueness<br />
Java class name<br />
Number corresponding to build target
LANCEMENT DE VOTRE APPS<br />
• Fonctionnalitées embarquées<br />
• Tout nouveau projet a automatiquement un comportement <strong>de</strong> type “Hello World”<br />
• Etape d’execution<br />
• click-D � Run As �<br />
Android Applicaton<br />
• Rappel : Ne fermez pas l’émulateur<br />
après vos tests.<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
VISUALISATION DES SORTIES<br />
STANDARDS AVEC DDMS
LES BASES DE DDMS<br />
• Concepts<br />
• DDMS (Dalvik Debug Monitor Service) est un outils qui réalise plusieurs choses<br />
• Simule un appel entrant sur l’émulateur<br />
• Peut définir une position GPS dans l’émulateur<br />
• Voir les print et les erreurs <strong>de</strong> runtime<br />
• Définir la position & prendre <strong>de</strong>s screenshots<br />
<strong>de</strong> votre <strong>de</strong>vice Android<br />
• Utilisation simple<br />
• Démarrez DDMS<br />
• Window �<br />
Open Perspective � DDMS<br />
• Une fois cette opération faite,<br />
vous pourrez clicker sur “DDMS” en haut<br />
à droite d’eclipse<br />
• Clickez sur “Java” poure revenir au co<strong>de</strong><br />
• Visualisation <strong>de</strong>s print<br />
• Observez dans la fenêtre ‘LogCat’ en bas<br />
• Type part of output into Filter field to see specific output<br />
jeudi 26 janvier 12
SORTIE DDMS<br />
(HELLOANDROID)<br />
• Co<strong>de</strong><br />
• Ajoutez un System.out.println<br />
Dans le main <strong>de</strong> la métho<strong>de</strong><br />
onCreate<br />
• Observez le co<strong>de</strong> dans la copie<br />
d’écran <strong>de</strong> la page précé<strong>de</strong>nte<br />
• La métho<strong>de</strong> onCreate et le reste<br />
sera abordé plus tard<br />
jeudi 26 janvier 12<br />
Output of System.out.println<br />
Entered so it is easier to find specific output among<br />
the many informational messages that emulator prints
LANCEMENT D’UNE APPS SUR<br />
jeudi 26 janvier 12<br />
UN PÉRIPHÉRIQUE ANDROID
LANCEMENT<br />
• Concept<br />
• La plupart <strong>de</strong>s tests que vous ferez seront réalisé dans l’émulateur Android. Parfois vous<br />
aurez besoin, <strong>de</strong> faire <strong>de</strong>s tests sur un VRAI <strong>de</strong>vice pour tester la compatibilité, la caméra<br />
(Réalité augmenté), le GPS, la liste <strong>de</strong>s contacts, ...<br />
• Vous <strong>de</strong>vez premièrement réaliser un package d’application signé (YourApp.apk). Ensuite, il y a plusieurs<br />
option pour l’envoyer sur le périphérique<br />
• Options<br />
• Couverte maintenant<br />
• Connexion USB, et adb pour la déployer<br />
• Couverte plus tard<br />
• Soumettre une application à l’Android Market<br />
• En autoformation ;)<br />
• Par l’envoie d’une apk par un email lu sur le téléphone<br />
• Déploiement <strong>de</strong> l’apps (fichier apk) sur un site web, et connexion sur ce site pour télécharger le fichier.<br />
( Il faut définir le type MIME à application/vnd.android.package-archive )<br />
jeudi 26 janvier 12
VIA L’USB<br />
• Prérequis : il faut installer les drivers pour le périphérique Android correspondant.<br />
• Brancher le <strong>de</strong>vice<br />
• Les OS récents <strong>de</strong>vraient trouver le driver automatiquement, sinon le télécharger à<br />
partir du site du constructeur :<br />
http://<strong>de</strong>veloper.android.com/sdk/oem-usb.html<br />
• Etapes<br />
• Sur le <strong>de</strong>vice Android<br />
• Dans préférence, passez en mo<strong>de</strong> <strong>de</strong>bug USB<br />
• Autorisez les sources inconnues<br />
• Eclipse<br />
• Exportez un package d’application signé (YourApp.apk)<br />
• adb<br />
• Allez dans sdk-install-dir\tools (où mettez ce chemin dans le PATH)<br />
• Lancez “adb install YourApp.apk”<br />
jeudi 26 janvier 12
CONFIGURATION DU DEVICE<br />
• Passer en mo<strong>de</strong> <strong>de</strong>bug USB<br />
• Settings � Applications �<br />
Development<br />
• Nécessaire : USB <strong>de</strong>bugging<br />
• permet au PC <strong>de</strong> se connecter en USB<br />
• Optionel: Stay awake<br />
• Le <strong>de</strong>vice ne passera pas en mo<strong>de</strong> eco<br />
• Optionel: Allow mock locations<br />
• Autorise le PC à envoyer <strong>de</strong> faux<br />
signaux GPS<br />
• Autoriser les sources inconnues<br />
• Settings � Applications �<br />
Unknown sources<br />
jeudi 26 janvier 12
EXPORTER UN PACKAGE<br />
• A faire à chaque fois : Export<br />
• click-D Eclipse project<br />
• Android Tools � Export<br />
Signed Application Package<br />
• Uniquement la première: définition d’une clé<br />
• Il vous sera <strong>de</strong>mandé <strong>de</strong> donner l’adresse<br />
d’un fournisseur <strong>de</strong> clé et un mot <strong>de</strong><br />
passe. La clé sera crée et l’apps signée, ce<br />
qui est un format vali<strong>de</strong> mais elle ne sera<br />
pas certifié par un organisme <strong>de</strong><br />
confiance.<br />
jeudi 26 janvier 12
INSTALLATION AVEC ADB<br />
• Connectez le <strong>de</strong>vice en USB<br />
• Ouvrez une fenêtre <strong>de</strong> comman<strong>de</strong><br />
• Windows Start Menu � Run � cmd<br />
• Allez dans le répertoire du SDK “platform-tools”<br />
• ..\android-sdk\platform-tools<br />
• Exécutez “adb install YourApp.apk”<br />
• > adb install HelloAndroid.apk<br />
1439 KB/s (13262 bytes in 0.009s)<br />
pkg: /data/local/tmp/HelloAndroid.apk<br />
Success<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
LANCEMENT DE L’APP<br />
• Allez dans applications ou installed<br />
apps<br />
• Tapez new app<br />
• Rappelez vous du nom humain<br />
donné à votre appli lors <strong>de</strong> sa<br />
création (Application Name)<br />
c’est celui qui apparait ici.<br />
• Pour mettre à jour le programme<br />
• Désinstallez au préalable la<br />
précé<strong>de</strong>nte version<br />
• Settings � Applications<br />
� YourApp � Uninstall
jeudi 26 janvier 12<br />
CONCLUSION
RÉSUMÉ<br />
• Installation <strong>de</strong>s logiciels (venez avec vos PC la prochaine fois si vous voulez)<br />
• Java 6, Eclipse, Android SDK, Eclipse ADT plugin<br />
• Mise à jour <strong>de</strong> vos Bookmarks pour la doc<br />
• Developer’s Gui<strong>de</strong> et + à <strong>de</strong>veloper.android.com<br />
• Mise à jour et configuration <strong>de</strong>s logiciels<br />
• Adresse du SDK dans Eclipse<br />
• Mise à jour <strong>de</strong>s composants via le SDK & AVD Manager<br />
• Définition d’au moins une AVD pour lancer vos apps sur un émulateur<br />
• Lancement d’une apps<br />
• Sur l’émulateur (la plupart du tps). click-D project, Run As � Android Application.<br />
• Sur le <strong>de</strong>vice (<strong>de</strong> tps en tps). construction d’un apk signé et utilisation d’adb.<br />
• Réalisation d’une nouvelle app<br />
• File � New � Project � Android � Android Project<br />
• Visualisation <strong>de</strong> la sortie d’écran <strong>de</strong> print<br />
• Dans la fenêtre LogCat <strong>de</strong> DDMS<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
QUESTIONS?
CONCEPTS DE BASE DE LA<br />
PROGRAMMATION ANDROID<br />
jeudi 26 janvier 12<br />
<strong>David</strong> <strong>Defour</strong><br />
<strong>Université</strong> <strong>de</strong> <strong>Perpignan</strong><br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/
RÉSUMÉ DU COURS<br />
• Réaliser & tester un projet Android<br />
• Structure <strong>de</strong> base d’un programme<br />
• Layout Java<br />
• Layout XML<br />
• Eclipse ADT visual layout editor<br />
• Layout Hybrid<br />
• Résumé <strong>de</strong> la structure d’un Project<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
RÉALISER UN PROJET<br />
ANDROID
PETIT RAPPEL<br />
• Déjà installé<br />
• Java 6<br />
• Eclipse<br />
• Android SDK<br />
• Eclipse ADT Plugin<br />
• Déjà configuré<br />
• Les composants SDK d’Android sont à jour<br />
• Eclipse préférences<br />
• Adresse du SDK Android définie<br />
• Au moins 1 AVD (Android Virtual Device) définit<br />
• Documentation<br />
• http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/<strong>de</strong>veloping/in<strong>de</strong>x.html<br />
• http://<strong>de</strong>veloper.android.com/reference/packages.html<br />
jeudi 26 janvier 12
RÉALISER VOTRE PROPRE<br />
PROJET ANDROID: LES BASES<br />
• Concepts<br />
• Lors <strong>de</strong> la création d’une nouvelle apps, elle dispose déjà <strong>de</strong>s fonctionnalités du<br />
‘HelloWorld’.<br />
• So, you can create and test an app without knowing syntax (which is not<br />
discussed until next tutorial section)<br />
• Steps<br />
• File � New � Project � Android � Android Project<br />
• Once you do this once, next time you<br />
can do File � New � Android Project<br />
• Fill in options as shown on next page<br />
• Run new project as shown previously<br />
• R-click � Run As �<br />
Android Application<br />
jeudi 26 janvier 12
DÉFINITION DES OPTIONS<br />
DU PROJETS<br />
• Paramétrage d’un nouveau projet Android<br />
• Project Name<br />
• Nom du projet sous eclipse, suivez votre propre convention.<br />
• Build Target<br />
• Version d’Android que vous souhaitez utiliser. Pour la plupart <strong>de</strong>s téléphone, choisissez 2.2 ce qui est le plus<br />
utilisé dans le mon<strong>de</strong>.<br />
• Application name<br />
• Nom <strong>de</strong> l’apps lisible par l’humain, le titre sera visible sur la barre Android.<br />
• Package name<br />
• L’application sur un <strong>de</strong>vice Android doit avoir un nom <strong>de</strong> paquet unique. Une façon <strong>de</strong> procé<strong>de</strong>r est <strong>de</strong><br />
faire : com.yourCompany.project<br />
• Create Activity<br />
• Le nom <strong>de</strong> la classe java la plus haute<br />
• Min SDK Version<br />
• Numéro qui doit correspondre au Build Target.<br />
Plus <strong>de</strong> détails à http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/appendix/api-levels.html<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
DÉFINITION DES OPTIONS<br />
DU PROJETS<br />
Eclipse project name<br />
Android version that you want to run on<br />
Human-readable app name<br />
Package. Use naming convention to ensure uniqueness<br />
Java class name<br />
Number corresponding to build target
LANCEMENT DE VOTRE APPS<br />
• Fonctionnalitées embarquées<br />
• Tout nouveau projet a automatiquement un comportement <strong>de</strong> type “Hello World”<br />
• Etape d’execution<br />
• click-D � Run As �<br />
Android Applicaton<br />
• Rappel : Ne fermez pas l’émulateur<br />
après vos tests.<br />
jeudi 26 janvier 12
LANCER UNE NOUVELLE APP<br />
SUR UN DEVICE ANDROID<br />
• Apps non signée : trivial<br />
• Brancher le téléphone et la lancer à partir d’Eclipse<br />
• Etapes<br />
jeudi 26 janvier 12<br />
• Configurer le téléphone pour accepter <strong>de</strong>s apps non vérifiées<br />
• Arrêter l’émulateur<br />
• Brancher le dévice<br />
• Click-D «project»<br />
• Run As � Android Application<br />
• Cela installe et lance l’apps. L’apps est laissée sur le <strong>de</strong>vice<br />
même une fois celui-ci débranché.
CONFIGURATION DU DEVICE<br />
• Passer en mo<strong>de</strong> <strong>de</strong>bug USB<br />
• Settings � Applications �<br />
Development<br />
• Nécessaire : USB <strong>de</strong>bugging<br />
• permet au PC <strong>de</strong> se connecter en USB<br />
• Optionel: Stay awake<br />
• Le <strong>de</strong>vice ne passera pas en mo<strong>de</strong> eco<br />
• Optionel: Allow mock locations<br />
• Autorise le PC à envoyer <strong>de</strong> faux<br />
signaux GPS<br />
• Autoriser les sources inconnues<br />
• Settings � Applications �<br />
Unknown sources<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
STRUCTURE D’UN<br />
PROGRAMME
STRUCTURE GÉNÉRALE<br />
(COMMUNE À TOUTES LES<br />
package com.companyname.projectname;<br />
import android.app.Activity;<br />
import android.os.Bundle;<br />
import android.widget.SomeLayoutOrView;<br />
APPROCHES)<br />
There is no need to type the import statements by hand. Just use the classes in your co<strong>de</strong>, and when<br />
Eclipse marks the line as an error, click on the light bulb at the left, or hit Control-1, then choose to have<br />
Eclipse insert the import statements for you.<br />
public class SomeName extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
SomeLayoutOrView view = createOrGetView();<br />
...<br />
setContentView(view);<br />
}<br />
...<br />
}<br />
jeudi 26 janvier 12<br />
Apps are frequently shut down by the <strong>de</strong>vice. This lets<br />
you remember some info about the previous invocation.<br />
Covered in later lectures, but for now, just know that you<br />
should always call super.onCreate as first line of<br />
onCreate.<br />
I also follow a few official Android coding conventions here (4-space in<strong>de</strong>ntation, no *’s in imports, {’s on same line as previous co<strong>de</strong>, @Overri<strong>de</strong> where appropriate). Conventions<br />
are strictly enforced in official co<strong>de</strong>, and are used in all examples and tutorials. So, you might as well follow the conventions from the beginning. Follow these simple ones for<br />
now, and a later lecture will give coding convention <strong>de</strong>tails and provi<strong>de</strong> an Eclipse preferences file to help with them.
LES 3 APPROCHES<br />
PRINCIPALES<br />
• Java<br />
• Définition directement en Java <strong>de</strong>s Strings Strings, window layout window, création <strong>de</strong>s boîtes<br />
<strong>de</strong> contrôle, et assignation <strong>de</strong>s event handlers. (~ Programmation swing)<br />
• XML<br />
• Définition à l’ai<strong>de</strong> <strong>de</strong> fichiers XML les Strings, window layout, création <strong>de</strong>s boîtes <strong>de</strong><br />
contrôle, et assignation <strong>de</strong>s event handlers. Les métho<strong>de</strong>s Java liront le layout à partir du<br />
fichier XML et le à setContentView.<br />
• Hybri<strong>de</strong><br />
• Utilisation <strong>de</strong>s fichiers XML pour la définition <strong>de</strong>s Strings, window layout et la création <strong>de</strong>s<br />
boîtes <strong>de</strong> contrôle. Utilisation <strong>de</strong> Java pour l’assignation <strong>de</strong>s event handlers.<br />
• Exemples dans ce tutoriel<br />
• Le bouton qui dit “Show Greeting”. Un petit message popup apparaîtra lorsque le bouton<br />
sera pressé.<br />
• Implémenté selon les 3 façons.<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
APPROCHE JAVA: SCHÉMA<br />
public class SomeName extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
String message = "...";<br />
LinearLayout window = new LinearLayout(this);<br />
window.setVariousAttributes(…);<br />
Button b = new Button(this);<br />
b.setText("Button Label");<br />
b.setOnClickListener(new SomeHandler());<br />
mainWindow.addView(b);<br />
...<br />
setContentView(window);<br />
}<br />
private class SomeHandler implements OnClickListener {<br />
@Overri<strong>de</strong><br />
public void onClick(View clickedButton) {<br />
doSomething(...);<br />
}<br />
} }<br />
OnClickListener is a public inner class insi<strong>de</strong> View. But, as long as you import android.view.View.OnClickListener, you use it just<br />
like a normal class. And, remember that Eclipse helps you with imports: just type in the class name, then either click on the light<br />
bulb or hit Control-1 to have Eclipse insert the proper import statements for you.
APPROCHE XML: SCHÉMA<br />
• Java<br />
public class SomeClass extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
}<br />
public void handlerMethod(View clickedButton) {<br />
String someName = getString(R.string.some_name);<br />
doSomethingWith(someName);<br />
} }<br />
• XML<br />
jeudi 26 janvier 12<br />
res/values/strings.xml res/layout/main.xml<br />
<br />
<br />
…<br />
…<br />
<br />
<br />
<br />
<br />
<br />
APPROCHE HYBRIDE: SCHÉMA<br />
• Java<br />
public class SomeClass extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
Button b = (Button)findViewById(R.id.button_id);<br />
b.setOnClickListener(new SomeHandler());<br />
}<br />
private class SomeHandler implements OnClickListener {<br />
@Overri<strong>de</strong><br />
public void onClick(View clickedButton) {<br />
doSomething(...);<br />
}<br />
} }<br />
• XML<br />
• On donne un ID aux controls qui ont besoin d’un handlers<br />
• NE PAS utiliser android:onClick pour attribuer un handler<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
LAYOUT JAVA
CONCEPTS<br />
• Approche<br />
• Définition directement en Java <strong>de</strong>s Strings Strings, window layout window,<br />
création <strong>de</strong>s boîtes <strong>de</strong> contrôle, et assignation <strong>de</strong>s event handlers. (~<br />
Programmation swing)<br />
• Avantages<br />
• Proche <strong>de</strong>s métho<strong>de</strong>s <strong>de</strong> <strong>de</strong>v sur <strong>de</strong>ktop. (~ Swing, SWT & AWT).<br />
• Bien pour les layouts dynamique (ex: qui change en fonction fonction du<br />
programme).<br />
• Inconvénients<br />
• Difficile à maintenir (~discutable, mais il y a consensus)<br />
• Fonctionnement chaotique avec I18N<br />
• Pas recommandé sauf pour les layouts dynamiques<br />
• Acceptable pour l’App Store sous réserve d’un bon fonctionnement (il n’y a<br />
pas <strong>de</strong> police qui traque les mauvais élèves/co<strong>de</strong>urs).<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
CODE (CORPS)<br />
public class SayHelloJava extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
String appName = "SayHello Application";<br />
String windowText =<br />
"Press the button below to receive " +<br />
"a friendly greeting from Android.";<br />
String buttonLabel = "Show Greeting";<br />
LinearLayout mainWindow = new LinearLayout(this);<br />
mainWindow.setOrientation(LinearLayout.VERTICAL);<br />
setTitle(appName);<br />
TextView label = new TextView(this);<br />
label.setText(windowText);<br />
mainWindow.addView(label);<br />
Button greetingButton = new Button(this);<br />
greetingButton.setText(buttonLabel);<br />
greetingButton.setOnClickListener(new Toaster());<br />
mainWindow.addView(greetingButton);<br />
setContentView(mainWindow);<br />
}
}<br />
jeudi 26 janvier 12<br />
CODE (EVENT HANDLER)<br />
private class Toaster implements OnClickListener {<br />
@Overri<strong>de</strong><br />
public void onClick(View clickedButton) {<br />
String greetingText = "Hello from Android!";<br />
Toast tempMessage =<br />
Toast.makeText(SayHelloJava.this,<br />
greetingText,<br />
Toast.LENGTH_SHORT);<br />
tempMessage.show();<br />
}
RÉSULTAT SUR L’ ÉMULATEUR<br />
• click-D, Run As � Android Application<br />
jeudi 26 janvier 12
RÉSULTATS SUR UN DEVICE<br />
• Configurez le <strong>de</strong>vice<br />
• Arrêter l’émulateur, branchez le <strong>de</strong>vice<br />
• Click-D project, Run As � Android Application<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
LAYOUT XML
CONCETS<br />
• Approche<br />
• Définition à l’ai<strong>de</strong> <strong>de</strong> fichiers XML les Strings, window layout, création <strong>de</strong>s boîtes <strong>de</strong><br />
contrôle, et assignation <strong>de</strong>s event handlers.<br />
• Définition <strong>de</strong>s layout et contrôles dans res/layout/main.xml<br />
• Définition <strong>de</strong>s Strings dans res/values/strings.xml<br />
• Avantages<br />
• Plus facile à maintenir<br />
• Bonne compatibilité avec I18N<br />
• Possibilité d’utiliser l’éditeur Visuel d’Eclipse<br />
• Approche Standard/recommndée<br />
(avec l’approche hybri<strong>de</strong>)<br />
• Inconvénients<br />
• Ne fonctionne pas avec les layouts dynamiques<br />
jeudi 26 janvier 12
PLUS DE DÉTAILS<br />
• res/layout/main.xml<br />
• Définit le layout et le controls à l’ai<strong>de</strong> d’une <strong>de</strong>scription XML<br />
• Define controls<br />
• Fait référence aux strings (<strong>de</strong> strings.xml) avec @string/string_name<br />
• Assigne un event handler avec android:onClick<br />
• res/values/strings.xml<br />
• Définit les strings utilisées dans le GUI ou qui peuvent changer avec I18N<br />
res/layout/main.xml<br />
• Co<strong>de</strong> Java<br />
• Fait référence aux layout avec R.layout.main<br />
• Fait référence aux strings avec getString(R.string.string_name)<br />
• Fait référence aux controls avec findViewById(R.id.some_id)<br />
• Plus d’info<br />
• http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/topics/ui/<strong>de</strong>claring-layout.html<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
LAYOUT DU PROJET<br />
Refers to layout <strong>de</strong>fined in res/layout/main.xml with<br />
R.layout.main.<br />
Refers to strings <strong>de</strong>fined in res/values/strings.xml with<br />
getString(R.string.string_name)<br />
Defines screen layout and GUI controls. Optionally assigns event<br />
handlers to controls.<br />
Refers to strings <strong>de</strong>fined in res/values/strings.xml with @string/<br />
string_name<br />
Conventional for main file to be called main.xml, but not required. If it is<br />
foo.xml, then Java uses R.layout.foo. As we will see later, complex apps<br />
have several layout files for different screens.<br />
Defines strings that are either used in GUI controls or that might<br />
change with internationalization.
RES/LAYOUT/MAIN.XML<br />
<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12<br />
These attributes (android:orientation, etd.)<br />
are <strong>de</strong>fined in JavaDoc API for<br />
LinearLayout.<br />
These strings are <strong>de</strong>fined in res/values/<br />
strings.xml<br />
This must be a public method in main class, have a void<br />
return type, and take a View as argument. No interface<br />
needs to be implemented, as it does with event handlers<br />
referred to in Java co<strong>de</strong>.
RES/VALUES/STRINGS.XML<br />
<br />
<br />
Say Hello Application<br />
<br />
Press the button below to receive<br />
a friendly greeting from Android.<br />
<br />
Show Greeting<br />
Hello from Android!<br />
<br />
jeudi 26 janvier 12<br />
app_name is special, pre<strong>de</strong>fined name (although it can be<br />
overrid<strong>de</strong>n in AndroidManifest.xml)<br />
All the rest are <strong>de</strong>veloper-specified names.<br />
main.xml refers to this with @string/greeting_text<br />
Java refers to this with getString(R.string.greeting_text)<br />
Eclipse auto-completion will recognize the names when editing other<br />
files that use them.
}<br />
jeudi 26 janvier 12<br />
CODE (JAVA)<br />
public class SayHelloXml extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
}<br />
public void showToast(View clickedButton) {<br />
String greetingText = getString(R.string.greeting_text);<br />
Toast tempMessage =<br />
Toast.makeText(this, greetingText,<br />
Toast.LENGTH_SHORT);<br />
tempMessage.show();<br />
}
• Dans l’émulateur<br />
• Click-D project, Run As �<br />
Android Application<br />
RÉSULTATS<br />
• Apparence & comportement i<strong>de</strong>ntique à l’exemple tout Java<br />
• Sur le <strong>de</strong>vice<br />
• Configurez le téléphone<br />
• Arrêtez l’émulateur et branchez le <strong>de</strong>vice<br />
• Click-D project, Run As � Android Application<br />
jeudi 26 janvier 12<br />
• Apparence & comportement i<strong>de</strong>ntique à l’exemple tout Java
jeudi 26 janvier 12<br />
ECLIPSE ADT<br />
VISUAL LAYOUT EDITOR
ECLIPSE VISUAL GUI BUILDER &<br />
EDITOR<br />
• Invocation<br />
• Lors <strong>de</strong> l’édition du main.xml, clickez sur Graphical Layout<br />
• Fonctionnalités<br />
• Peut changez interactivement les attributs du layout (vertical/horizontal, caractéristiques, etc.)<br />
• Peut faire du drag&drop à partir <strong>de</strong> la palette <strong>de</strong> contrôle GUI disponible<br />
• Peut définir interactivement les caractéristiques <strong>de</strong> contrôle (couleurs, remplissage, event<br />
handler, etc.)<br />
• Prévisualisation<br />
• Attention<br />
• Bien que l’éditeur visuel est très pratique, cela ne vous dispense pas <strong>de</strong> l’édition manuelle <strong>de</strong>s<br />
fichiers XML, pour définir l’in<strong>de</strong>ntation, l’ordre <strong>de</strong>s attributs ....<br />
• Plus d’info<br />
• http://tools.android.com/recent<br />
• http://www.youtube.com/watch?v=Oq05KqjXTvs<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
ECLIPSE VISUAL LAYOUT<br />
EDITOR
jeudi 26 janvier 12<br />
HYBRID LAYOUT
• Approches<br />
CONCEPTS<br />
• Utilisation <strong>de</strong>s fichiers XML pour la définition <strong>de</strong>s Strings,<br />
window layout et la création <strong>de</strong>s boîtes <strong>de</strong> contrôle.<br />
• Utilisation <strong>de</strong> Java pour l’assignation <strong>de</strong>s event handlers.<br />
• Avantages<br />
• Les mêmes que pour l’approche XML<br />
• Mais, puisque les event handler ont besoin d’être édité en Java, il<br />
y a plus <strong>de</strong> sens <strong>de</strong> les assignés en aussi en Java.<br />
• Inconvénients<br />
jeudi 26 janvier 12<br />
• Ne fonctionne pas avec les layouts dynamiques
RES/LAYOUT/MAIN.XML<br />
<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12<br />
We <strong>de</strong>fine an id for the button, so that the<br />
button can be referred to in Java co<strong>de</strong> with<br />
findViewById(R.id.greeting_button)<br />
We do not assign an event handler to the button, as<br />
we did in the previous example.
RES/VALUES/STRINGS.XML<br />
<br />
<br />
Say Hello Application<br />
<br />
Press the button below to receive<br />
a friendly greeting from Android.<br />
<br />
Show Greeting<br />
Hello from Android!<br />
<br />
jeudi 26 janvier 12<br />
No changes from previous example.
jeudi 26 janvier 12<br />
CODE (JAVA)<br />
public class SayHelloHybrid extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
Button greetingButton =<br />
(Button)findViewById(R.id.greeting_button);<br />
greetingButton.setOnClickListener(new Toaster());<br />
}<br />
private class Toaster implements OnClickListener {<br />
@Overri<strong>de</strong><br />
public void onClick(View clickedButton) {<br />
String greetingText = getString(R.string.greeting_text);<br />
Toast tempMessage =<br />
Toast.makeText(SayHelloHybrid.this,<br />
greetingText,<br />
Toast.LENGTH_SHORT);<br />
tempMessage.show();<br />
}<br />
}}<br />
You must call setContentView before<br />
calling findViewById. If you call<br />
findViewById first, you get null.
• Dans l’émulateur<br />
• Click-D project, Run As �<br />
Android Application<br />
RÉSULTATS<br />
• Apparence & comportement i<strong>de</strong>ntique à l’exemple tout Java<br />
• Sur le <strong>de</strong>vice<br />
• Configurez le téléphone<br />
• Arrêtez l’émulateur et branchez le <strong>de</strong>vice<br />
• Click-D project, Run As � Android Application<br />
jeudi 26 janvier 12<br />
• Apparence & comportement i<strong>de</strong>ntique à l’exemple tout Java
jeudi 26 janvier 12<br />
CONCLUSION
jeudi 26 janvier 12<br />
PROJECT LAYOUT<br />
Refers to layout <strong>de</strong>fined in res/layout/main.xml with<br />
R.layout.main.<br />
Refers to controls <strong>de</strong>fined in res/layout/main.xml with<br />
findViewById(R.id.some_id)<br />
Refers to strings <strong>de</strong>fined in res/values/strings.xml with<br />
getString(R.string.string_name)<br />
Defines screen layout and GUI controls. Optionally assigns event<br />
handlers to controls.<br />
Refers to strings <strong>de</strong>fined in res/values/strings.xml with @string/<br />
string_name<br />
Defines strings that are either used in GUI controls or that might<br />
change with internationalization.
RÉSUMÉ<br />
• XML<br />
• res/layout/main.xml<br />
• Définit les propriétés du layout et le contrôle du GUI.<br />
• Parfois assigne <strong>de</strong>s event handlers à du contrôle<br />
• res/values/strings.xml<br />
• Définit les Strings utilisés dans le GUI ou pour le I18N.<br />
• Java<br />
• La classe principale étend la classe Action<br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
maybeFindControlAndAssignHandler(…);<br />
}<br />
• Le Event handler prend un View en argument<br />
• Si il est assigné en Java, il faut implémenter<br />
OnClickListener (ou un autre Listener)<br />
jeudi 26 janvier 12<br />
Call setContentView<br />
before calling<br />
findViewById.<br />
Widget event handling is<br />
covered in <strong>de</strong>tail in next<br />
tutorial section.
jeudi 26 janvier 12<br />
QUESTIONS?
jeudi 26 janvier 12<br />
WIDGET EVENT HANDLING<br />
<strong>David</strong> <strong>Defour</strong><br />
<strong>Université</strong> <strong>de</strong> <strong>Perpignan</strong><br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/
RÉSUMÉ DU COURS<br />
• Utilisation d’une classe Listener séparée<br />
• Utilisation d’une inner classe nommée<br />
• Utilisation d’une inner classe anonyme<br />
• Utilisation <strong>de</strong> l’ Activity<br />
• et implémentation <strong>de</strong> l’interface Listener<br />
• Utilisation <strong>de</strong> l’ Activity<br />
• et spécification <strong>de</strong>s métho<strong>de</strong>s dans le fichier layout<br />
(main.xml)<br />
• Copie et rennomage <strong>de</strong> projet Android sous Eclipse<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
UTILISATION D’UNE CLASSE<br />
LISTENER SÉPARÉE
CONCEPTS<br />
• Buts<br />
• Changer la couleurs d’un TextView lorsqu’un Button ou RadioButton est pressé.<br />
Gestion <strong>de</strong> différentes couleurs en fonction du bouton.<br />
• Approches<br />
• Utilisation d’une classe externe qui implémente View.OnClickListener<br />
• Import android.view.View.OnClickListener, et dit alors “implements OnClickListener”<br />
• Avantages<br />
• Il est possible <strong>de</strong> donner <strong>de</strong>s arguments pour changer le comportement<br />
• La séparation <strong>de</strong>s classes généralement ne promouvoit qu’un couplage faible<br />
• Si le gestionnaire d’événement peut s’appliquer à différents contrôles, il peut être changé<br />
indépendamment du reste <strong>de</strong> l’application..<br />
• Inconvénients<br />
• Si vous voulez appeler du co<strong>de</strong> à partir du main Activity, vous aurez besoin <strong>de</strong><br />
références<br />
• En plus le co<strong>de</strong> dans le main Activity doit être public<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
RÉSUMÉ SUR LE LAYOUT<br />
Button<br />
Button<br />
Button<br />
Horizontal<br />
RadioGroup<br />
(Containing 3 RadioButtons)<br />
TextView<br />
(No text, but controls will<br />
change the background<br />
color of this region.)<br />
Vertical<br />
LinearLayout<br />
An upcoming tutorial section gives <strong>de</strong>tails on using layouts. However, you can<br />
do a pretty lot now by knowing just two simple things:<br />
1) You can make some pretty complex layouts by nesting horizontal and<br />
vertical layouts insi<strong>de</strong> each other.<br />
2) You can experiment interactively with the visual layout editor in Eclipse.<br />
Edit main.xml and click on Graphical Layout.
RES/LAYOUT/MAIN.XML<br />
<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12<br />
Overall layout is a vertical stack of graphical items.<br />
This part <strong>de</strong>fines the 3 buttons shown on the previous sli<strong>de</strong>.<br />
Each button is given an id so that it can be found in Java via<br />
findViewById, then assigned an event handler via<br />
setOnClickListener.<br />
The text (Button label) is taken from strings.xml instead of<br />
entered directly here, because the same label will also be used<br />
for RadioButtons.
jeudi 26 janvier 12<br />
RES/LAYOUT/MAIN.XML<br />
<br />
<br />
<br />
<br />
<br />
A horizontal RadioGroup gives the same layout as a<br />
horizontal LinearLayout, except that it contains only<br />
RadioButtons. A RadioGroup also means that only<br />
one of the RadioButtons insi<strong>de</strong> can be selected at<br />
any given time.
RES/LAYOUT/MAIN.XML<br />
<br />
<br />
jeudi 26 janvier 12<br />
This <strong>de</strong>fines the blank region at the bottom that will<br />
change colors when the Buttons or RadioButtons<br />
are clicked. I used a TextView because I might later<br />
want to put some text insi<strong>de</strong>.
RES/VALUES/STRINGS.XML<br />
<br />
<br />
Event Handling Example<br />
Red<br />
Blue<br />
Yellow<br />
<br />
jeudi 26 janvier 12<br />
main.xml refers to these names with @string/red_prompt, @string/<br />
blue_prompt, and @string/yellow_prompt.<br />
Each string is used as label for one Button and one RadioButton.
jeudi 26 janvier 12<br />
MAIN ACTIVITY CLASS<br />
public class Events1Example extends Activity {<br />
private View mColorRegion;<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
mColorRegion = findViewById(R.id.color_region);<br />
Button b1 = (Button)findViewById(R.id.button1);<br />
Button b2 = (Button)findViewById(R.id.button2);<br />
Button b3 = (Button)findViewById(R.id.button3);<br />
RadioButton r1 =<br />
(RadioButton)findViewById(R.id.radio_button1);<br />
RadioButton r2 =<br />
(RadioButton)findViewById(R.id.radio_button2);<br />
RadioButton r3 =<br />
(RadioButton)findViewById(R.id.radio_button3);<br />
This part just looks up the controls<br />
that were <strong>de</strong>fined in main.xml, and<br />
assigns them to variables. Note the<br />
Android coding convention that nonpublic<br />
instance variables (data<br />
members) start “m”.
}<br />
}<br />
jeudi 26 janvier 12<br />
MAIN ACTIVITY CLASS<br />
(CONTINUED)<br />
b1.setOnClickListener(new ColorSetter(Color.RED, this));<br />
b2.setOnClickListener(new ColorSetter(Color.BLUE, this));<br />
b3.setOnClickListener(new ColorSetter(Color.YELLOW, this));<br />
r1.setOnClickListener(new ColorSetter(Color.RED, this));<br />
r2.setOnClickListener(new ColorSetter(Color.BLUE, this));<br />
r3.setOnClickListener(new ColorSetter(Color.YELLOW, this));<br />
public void setRegionColor(int color) {<br />
mColorRegion.setBackgroundColor(color);<br />
}<br />
Since this method will be called<br />
by method in separate event<br />
handler class, it must be public.<br />
Assigns a separate class as the event handler for<br />
each of the Buttons and RadioButtons.<br />
Good news: you can pass arguments to the event<br />
handler (the colors) so that the same event<br />
handler class can have different behaviors for<br />
different controls.<br />
Bad news: you have to pass a reference to the<br />
main Activity (“this” above) so that the event<br />
handler can call back to co<strong>de</strong> in the Activity.
}<br />
jeudi 26 janvier 12<br />
EVENT HANDLER CLASS<br />
public class ColorSetter implements OnClickListener {<br />
private int regionColor;<br />
private Events1Example mainActivity;<br />
public ColorSetter(int regionColor,<br />
Events1Example mainActivity) {<br />
this.regionColor = regionColor;<br />
this.mainActivity = mainActivity;<br />
}<br />
@Overri<strong>de</strong><br />
public void onClick(View v) {<br />
mainActivity.setRegionColor(regionColor);<br />
}<br />
Event handler must store a reference to the main Activity so that it can call back to it.<br />
Another option in this particular case would be to pass the TextView to the event<br />
handler, but passing the main Activity is a more general solution.
jeudi 26 janvier 12<br />
RÉSULTATS DANS L’<br />
EMULATEUR
jeudi 26 janvier 12<br />
RÉSULTATS SUR UN DEVICE
jeudi 26 janvier 12<br />
UTILISATION D’UNE INNER<br />
CLASSE NOMMÉE
IDÉE<br />
• Buts<br />
• Changer la couleurs d’un TextView lorsqu’un Button ou RadioButton est<br />
pressé. Gestion <strong>de</strong> différentes couleurs en fonction du bouton.<br />
• I<strong>de</strong>m précé<strong>de</strong>nt<br />
• Approche<br />
• Utilisation d’une inner classe qui implémente View.OnClickListener<br />
• Avantages<br />
• Il est possible <strong>de</strong> donner <strong>de</strong>s arguments pour changer le comportement<br />
• La métho<strong>de</strong> du gestionnaire d’événement peut accé<strong>de</strong>r aux données<br />
privées <strong>de</strong> l’Activity. Pas besoin <strong>de</strong> référence pour appeler l’Activity.<br />
• Inconvénients<br />
• La classe Listener est dans le même fichier que l’activity, elles sont plus<br />
liées et ne peuvent pas être changées indépendamment l’une <strong>de</strong> l’autre.<br />
jeudi 26 janvier 12
XML FILES: IDEM PRÉCÉDENT<br />
• res/layout/main.xml<br />
• Définit un LinearLayout vertical qui contient 3 Buttons, un<br />
RadioGroup horizontal (avec 3 RadioButtons), et un<br />
TextView.<br />
• Les Buttons, RadioButtons, et TextView ont le même<br />
i<strong>de</strong>ntifiant auxquels ont peut faire référence dans le co<strong>de</strong><br />
Java<br />
• res/values/strings.xml<br />
jeudi 26 janvier 12<br />
• Définit le nom <strong>de</strong> l’application et les labels <strong>de</strong>s Buttons et<br />
RadioButtons
jeudi 26 janvier 12<br />
MAIN ACTIVITY CLASS<br />
public class Events2Example extends Activity {<br />
private View mColorRegion;<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
mColorRegion = findViewById(R.id.color_region);<br />
Button b1 = (Button)findViewById(R.id.button1);<br />
Button b2 = (Button)findViewById(R.id.button2);<br />
Button b3 = (Button)findViewById(R.id.button3);<br />
RadioButton r1 =<br />
(RadioButton)findViewById(R.id.radio_button1);<br />
RadioButton r2 =<br />
(RadioButton)findViewById(R.id.radio_button2);<br />
RadioButton r3 =<br />
(RadioButton)findViewById(R.id.radio_button3);<br />
Except for the class name, this top<br />
part of the Activity is exactly the same<br />
as the previous example.
}<br />
jeudi 26 janvier 12<br />
MAIN ACTIVITY CLASS<br />
b1.setOnClickListener(new ColorSetter(Color.RED, this));<br />
b2.setOnClickListener(new ColorSetter(Color.BLUE, this));<br />
b3.setOnClickListener(new ColorSetter(Color.YELLOW, this));<br />
r1.setOnClickListener(new ColorSetter(Color.RED, this));<br />
r2.setOnClickListener(new ColorSetter(Color.BLUE, this));<br />
r3.setOnClickListener(new ColorSetter(Color.YELLOW, this));<br />
private void setRegionColor(int color) {<br />
mColorRegion.setBackgroundColor(color);<br />
}<br />
Since this method will only be called<br />
by method in inner event handler<br />
class, it is allowed to be private.<br />
Note no closing brace. This class is not<br />
finished yet (continued on next sli<strong>de</strong>)<br />
Assigns an inner class as the event handler for each<br />
of the Buttons and RadioButtons.<br />
As with the previous example, you can pass<br />
arguments to the event handler (the colors) so that<br />
the same event handler class can have different<br />
behaviors for different controls.<br />
However, since the event handler is in the same<br />
class, you do not have to supply a reference to the<br />
main Activity class.
EVENT HANDLER CLASS<br />
(PARTIE DE MAIN ACTIVITY CLASS)<br />
}<br />
}<br />
jeudi 26 janvier 12<br />
private class ColorSetter implements OnClickListener {<br />
private int regionColor;<br />
public ColorSetter(int regionColor) {<br />
this.regionColor = regionColor;<br />
}<br />
@Overri<strong>de</strong><br />
public void onClick(View v) {<br />
setRegionColor(regionColor);<br />
}<br />
Closes off the main Activity class.<br />
Event handler can directly call methods in the main Activity,<br />
even if the method is private.
RÉSULTATS SUR L’ EMULATEUR<br />
jeudi 26 janvier 12<br />
Same as previous example.
jeudi 26 janvier 12<br />
RÉSULTAT SUR UN DEVICE<br />
Same as previous example.
jeudi 26 janvier 12<br />
UTILISATION D’UNE INNER<br />
CLASSE ANONYME POUR LA<br />
GESTION DES ÉVÉNEMENTS
CONCEPT<br />
• Buts<br />
• Changer la couleur aléatoirement du TextView lorsque le Button est préssé.<br />
• Approche<br />
• Utilisation d’une inner class anonyme qui implémente le Listener<br />
• Avantages<br />
• Si l’on part du principe que l’on a une classe par contrôle, on a les mêmes<br />
avantages qu’une inner classe nommée, mais en plus concis.<br />
• Approche que l’on retrouve dans Swing, SWT, AWT, and GWT.<br />
• Inconvénients<br />
• Si l’on applique le handler à plus d’un control, il faudra faire du copié/collé du co<strong>de</strong><br />
que handler.<br />
• Ce type d’approche doit s’appliquer seulement pour un contrôle unique<br />
• Si le co<strong>de</strong> pour les handler est long, cela rend le co<strong>de</strong> plus difficile à lire en l’inlinant.<br />
• Approche utilisée seulement lorsque le co<strong>de</strong> du handler est court<br />
jeudi 26 janvier 12
RES/LAYOUT/MAIN.XML<br />
<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12
RES/VALUES/STRINGS.XML<br />
<br />
<br />
Event Handling Example<br />
Random Color<br />
<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
ACTIVITY CLASS 1:<br />
INNER CLASS NOMMÉE<br />
public class Events3Example extends Activity {<br />
private View mColorRegion;<br />
private int[] mColorChoices =<br />
{ Color.BLACK, Color.BLUE, ...};<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
mColorRegion = findViewById(R.id.color_region);<br />
Button colorButton =<br />
(Button)findViewById(R.id.color_button);<br />
colorButton.setOnClickListener(new ColorRandomizer());<br />
}<br />
private void setRegionColor(int color) {<br />
mColorRegion.setBackgroundColor(color);<br />
}<br />
There is nothing wrong with this approach.<br />
However, this event handler class is only<br />
used on this line of co<strong>de</strong>. Furthermore, the<br />
co<strong>de</strong> for ColorRandomizer (next page) is<br />
relatively short. So, you can make it a bit<br />
more concise with an anonymous inner class.
}<br />
}<br />
jeudi 26 janvier 12<br />
ACTIVITY CLASS 1:<br />
INNER CLASS NOMMÉE<br />
private class ColorRandomizer<br />
implements OnClickListener {<br />
@Overri<strong>de</strong><br />
public void onClick(View v) {<br />
Random generator = new Random();<br />
int in<strong>de</strong>x = generator.nextInt(mColorChoices.length);<br />
setRegionColor(mColorChoices[in<strong>de</strong>x]);<br />
}
jeudi 26 janvier 12<br />
ACTIVITY CLASS 1:<br />
INNER CLASS ANONYME<br />
public class Events3Example extends Activity {<br />
private View mColorRegion;<br />
private int[] mColorChoices =<br />
{ Color.BLACK, Color.BLUE, ...};<br />
private void setRegionColor(int color) {<br />
mColorRegion.setBackgroundColor(color);<br />
}<br />
See next page for onCreate
jeudi 26 janvier 12<br />
ACTIVITY CLASS 1:<br />
INNER CLASS ANONYME<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
mColorRegion = findViewById(R.id.color_region);<br />
Button colorButton =<br />
(Button)findViewById(R.id.color_button);<br />
colorButton.setOnClickListener(new OnClickListener() {<br />
@Overri<strong>de</strong><br />
public void onClick(View v) {<br />
Random generator = new Random();<br />
int in<strong>de</strong>x = generator.nextInt(mColorChoices.length);<br />
setRegionColor(mColorChoices[in<strong>de</strong>x]);<br />
}<br />
});<br />
} This <strong>de</strong>fines the class and instantiates it all in one fell swoop. If you have never seen anonymous inner<br />
classes before, the confusion is probably not worth the co<strong>de</strong> savings over a named inner class.<br />
However, once you are used to it, it is more concise and arguably easier to un<strong>de</strong>rstand because the<br />
behavior is shown where it is used. This approach is very commonly used by Swing, SWT, AWT, and<br />
GWT programmers. This is also very analogous to anonymous functions (closures) that are wi<strong>de</strong>ly<br />
used in functional programming languages.
RÉSULTATS SUR L’EMULATEUR<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
RÉSULTATS SUR UN DEVICE
jeudi 26 janvier 12<br />
GESTION DES ÉVÉNEMENTS AVEC<br />
L’ ACTIVITY QUI IMPLÉMENTE<br />
L’INTERFACE LISTENER
CONCEPT<br />
• Buts<br />
• Changer la couleur aléatoirement du TextView lorsque le Button est pressé<br />
• Approche<br />
• Avoir l’ Activity qui implémente l’interface Listener. Placer la métho<strong>de</strong> handler dans l’ Activity.<br />
Appeler setOnClickListener(this).<br />
• Avantages<br />
• Si l’app a un seul contrôle sur ce type <strong>de</strong> Listener, alors c’est la façon la plus simple et la plus<br />
rapi<strong>de</strong> <strong>de</strong> toutes les approches.<br />
• Inconvénients<br />
• Ne passe pas à l’échelle avec <strong>de</strong>s contrôles multiples sauf si l’on a <strong>de</strong>s comportements i<strong>de</strong>ntiques.<br />
• Si l’on assigne “this” comme handler pour plus d’un contrôle du même type Listener, alors la métho<strong>de</strong> onClick (ou<br />
autre) <strong>de</strong>viendra complexe pour déterminer quel contrôle a été clické<br />
• Cette métho<strong>de</strong> est a réserver pour <strong>de</strong>s apps qui ont un seul contrôle <strong>de</strong> ce type <strong>de</strong> Listener<br />
• Il n’est pas possible <strong>de</strong> passer <strong>de</strong>s arguments au Listener<br />
• Donc, fonctionne difficilement pour <strong>de</strong>s contrôles multiples<br />
jeudi 26 janvier 12
• res/layout/main.xml<br />
XML FILES:<br />
IDENTIQUE<br />
• Définit un LinearLayout vertical contenant un Button et un<br />
TextView.<br />
• Le Button et le TextView ont <strong>de</strong>s ids qui pourront être<br />
utilisés pour y faire référence dans le co<strong>de</strong> Java<br />
• res/values/strings.xml<br />
jeudi 26 janvier 12<br />
• Définit le nom <strong>de</strong> l’application et le label du Button
jeudi 26 janvier 12<br />
MAIN ACTIVITY CLASS<br />
public class Events5Example extends Activity<br />
implements OnClickListener {<br />
private View mColorRegion;<br />
private int[] mColorChoices =<br />
{ Color.BLACK, Color.BLUE, ... };<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
mColorRegion = findViewById(R.id.color_region);<br />
Button colorButton =<br />
(Button)findViewById(R.id.color_button);<br />
colorButton.setOnClickListener(this);<br />
}
}<br />
}<br />
jeudi 26 janvier 12<br />
MAIN ACTIVITY CLASS<br />
private void setRegionColor(int color) {<br />
mColorRegion.setBackgroundColor(color);<br />
@Overri<strong>de</strong><br />
public void onClick(View v) {<br />
Random generator = new Random();<br />
int in<strong>de</strong>x = generator.nextInt(mColorChoices.length);<br />
setRegionColor(mColorChoices[in<strong>de</strong>x]);<br />
}
jeudi 26 janvier 12<br />
RÉSULTAT SUR L’ÉMULATEUR<br />
Same as previous example.
jeudi 26 janvier 12<br />
RÉSULTAT SUR LE DEVICE<br />
Same as<br />
previous<br />
example.
jeudi 26 janvier 12<br />
GESTION DES ÉVÉNEMENTS<br />
EN INDIQUANT LA<br />
MÉTHODE DANS LE<br />
MAIN.XML
CONCEPTS<br />
• Buts<br />
• Changer la couleur aléatoirement du TextView lorsque le Button est pressé.<br />
• Approche<br />
• Placer la métho<strong>de</strong> dans l’ Activity. Ne pas implémenter d’interface Listener ou appeler<br />
setOnClickListener. Avoir un fichier layout (main.xml) qui spécifie la métho<strong>de</strong> handler via<br />
l’attribut android:onClick<br />
• Avantages<br />
• Part du principe que l’app a un seul contrôle <strong>de</strong> ce Listener type. Avantages (co<strong>de</strong> simple/court)<br />
i<strong>de</strong>ntique à l’approche précé<strong>de</strong>nte.<br />
• Plus consistant avec la stratégie “do layout in XML”<br />
• Il est possible <strong>de</strong> fournir plusieurs nom <strong>de</strong> métho<strong>de</strong>s pour différents contrôles.<br />
• Inconvénients<br />
• Il n’est toujours pas possible <strong>de</strong> passer <strong>de</strong>s arguments au Listener.<br />
• Moins clair pour le développeur Java pour qui la métho<strong>de</strong> est le handler du contrôle<br />
jeudi 26 janvier 12
RES/LAYOUT/MAIN.XML<br />
<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12<br />
This is the name of the event handler<br />
method in the main class. This method<br />
must have a void return type and take a<br />
View as an argument. However, the<br />
method name is arbitrary, and the main<br />
class need not implement any particular<br />
interface.
RES/VALUES/STRINGS.XML<br />
<br />
<br />
Event Handling Example<br />
Random Color<br />
<br />
jeudi 26 janvier 12<br />
Unchanged from the previous two examples
jeudi 26 janvier 12<br />
MAIN ACTIVITY CLASS<br />
public class Events6Example extends Activity {<br />
private View mColorRegion;<br />
private int[] mColorChoices =<br />
{ Color.BLACK, Color.BLUE, ... };<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
mColorRegion = findViewById(R.id.color_region);<br />
// No need to look up the button or assign event handler<br />
}
}<br />
}<br />
jeudi 26 janvier 12<br />
MAIN ACTIVITY CLASS<br />
private void setRegionColor(int color) {<br />
mColorRegion.setBackgroundColor(color);<br />
public void randomizeColor(View v) {<br />
Random generator = new Random();<br />
int in<strong>de</strong>x = generator.nextInt(mColorChoices.length);<br />
setRegionColor(mColorChoices[in<strong>de</strong>x]);<br />
}<br />
Matches method name given for<br />
android:onClick in main.xml
jeudi 26 janvier 12<br />
RÉSULTAT SUR L’ÉMULATEUR<br />
Same as previous example.
jeudi 26 janvier 12<br />
RÉSULTAT SUR LE DEVICE<br />
Same as<br />
previous<br />
example.
jeudi 26 janvier 12<br />
COPIE D’UN PROJET<br />
ANDROID SOUS ECLIPSE
ETAPES<br />
• Problème<br />
• Les projets dans ce tutoriel sont très proches les uns <strong>de</strong>s autres.<br />
• Vous voulez copié/renomé vos précé<strong>de</strong>nts projets au lieu <strong>de</strong> créer <strong>de</strong> nouveau projet et <strong>de</strong><br />
copié chaque partie <strong>de</strong> façon séparée<br />
• Mais, le noms <strong>de</strong>s paquets sur le <strong>de</strong>vice doit être unique<br />
• Le renommage <strong>de</strong>s paquets nécessite quelques précautions. Pas <strong>de</strong> vraie support dans Eclipse.<br />
• Etapes (l’ordre est important !)<br />
1. click-D sur le vieux projet. click-D et choississez Paste. New name.<br />
2. click-D nouveau projet, Android Tools � Rename Application Package. New<br />
name. Déselectionnez la classes Java, et laissez la sélection seulement pour le<br />
manifest. OK lorsque l’on vous <strong>de</strong>man<strong>de</strong> <strong>de</strong> mettre à jour la configuration.<br />
3. click-D src/projectName dans le nouveau projet. Refactor � Rename. OK<br />
lorsque l’on informe que le paquet existe.<br />
4. Optionnel : click-D dans l’Activity. Refactor � Rename.<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
CONCLUSION
APPROCHES: CONTRÔLES<br />
SIMPLES OU MULTIPLES<br />
• Situation<br />
• Le même co<strong>de</strong> <strong>de</strong> gestionnaire doit être appliqué à plusieurs contrôles<br />
• Options<br />
• Utiliser une classe gestionnaire d’événement séparée<br />
• Pros: possibilité <strong>de</strong> passer <strong>de</strong>s args au gestionnaire afin <strong>de</strong> customiser son<br />
comportement; plus facile à changer indépendamment <strong>de</strong> l’app principale<br />
• Cons: Si le gestionnaire appel du co<strong>de</strong> <strong>de</strong> l’ Activity, il faut utiliser “this” et rendre la<br />
métho<strong>de</strong> public<br />
• Utiliser une inner classe nommée<br />
• Pros: possibilité <strong>de</strong> passer <strong>de</strong>s arps au gestionnaire afin <strong>de</strong> customiser son<br />
comportement; pas besoins <strong>de</strong> “this” reference, la métho<strong>de</strong> peut être privée<br />
• C’est <strong>de</strong> mon point <strong>de</strong> vue la métho<strong>de</strong> la plus facile pour la gestion <strong>de</strong>s événement<br />
<strong>de</strong> type Widget<br />
• Cons: le gestionnaire est lié à l’Activity<br />
jeudi 26 janvier 12
APPROCHES: CONTRÔLE<br />
SIMPLE<br />
• Situation<br />
• Le co<strong>de</strong> du gestionnaire doit être appliqué à un seul contrôle<br />
• Options<br />
• Utilisation d’une inner classe anonyme<br />
• Pros: i<strong>de</strong>ntique à l’inner class nommée, et plus concise<br />
• Cons: + difficile pour les novices ou si le co<strong>de</strong> du handler est long<br />
• Mettre le handler dans l’ Activity, implémenter l’interface et appeler<br />
setOnClickListener(this)<br />
• Pros: co<strong>de</strong> simple<br />
• Cons: impossibilité <strong>de</strong> passer <strong>de</strong>s arguments au handler<br />
• Mettre le handler dans l’ Activity, pas d’interface, spécifier la métho<strong>de</strong> avec<br />
android:onClick dans le main.xml<br />
• Pros: 1 métho<strong>de</strong> par contrôle, mais différentes métho<strong>de</strong>s pour chaque contrôle.. Plus orientée<br />
XML, moins <strong>de</strong> co<strong>de</strong> Java<br />
• Cons: plus difficile pour les développeurs Java<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
BOUTON ET WIDGET<br />
CLICABLE<br />
<strong>David</strong> <strong>Defour</strong><br />
<strong>Université</strong> <strong>de</strong> <strong>Perpignan</strong><br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/
• Buttons<br />
RÉSUMÉ DU COURS<br />
• ImageButtons chacune avec un image unique<br />
• ImageButtons chacune avec 3 (normal/focused/pressée)<br />
images<br />
• RadioButtons avec OnClickListener sur chaque<br />
• RadioButtons avec OnCheckedChangeListener sur un<br />
RadioGroup<br />
• CheckBoxes<br />
• ToggleButtons<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
APPROCHE GÉNÉRALE<br />
POUR LES WIDGET
WIDGET LECTURES COMBINED<br />
IN SINGLE PROJECT<br />
• Main screen<br />
• Lets user choose screens on various Widget topics<br />
• Other screens<br />
• Correspond to separate lectures.<br />
• One screen for lecture on Buttons, another for lecture on Spinners, another for<br />
number input, etc.<br />
• Separate layout files<br />
• main.xml, buttons.xml, spinners.xml, etc. See next sli<strong>de</strong>.<br />
• Separate Java classes<br />
• WidgetActivity.java, ButtonActivity.java, SpinnerActivity.java, etc.<br />
• Shared strings file<br />
• strings.xml has separate sections for each lecture, but same file<br />
jeudi 26 janvier 12
LAYOUT FILES FOR WIDGET<br />
LECTURES<br />
• Separate layout files for each Activity<br />
• res/layout/main.xml<br />
• Gives layout for main screen. Loa<strong>de</strong>d with setContentView(R.layout.main);<br />
• res/layout/buttons.xml<br />
• Gives layout for screen on Button and related Widgets. Loa<strong>de</strong>d with<br />
setContentView(R.layout.buttons);<br />
• res/layout/spinners.xml<br />
• Gives layout for screen on Spinners (i.e., combo boxes). Loa<strong>de</strong>d with<br />
setContentView(R.layout.spinners);<br />
• Two common layout attributes<br />
• android:layout_width, android:layout_height<br />
• match_parent (fill up space in enclosing View)<br />
• wrap_content (use natural size)<br />
jeudi 26 janvier 12
SWITCHING ACTIVITIES:<br />
SUMMARY<br />
• Switches Activities with Intents<br />
• Main screen has buttons to navigate to other Activities<br />
• Return to original screen with phone’s “back” button<br />
• Syntax required to start new Activity<br />
• Java<br />
• Intent newActivity = new Intent(this, NewActivity.class);<br />
• startActivity(newActivity);<br />
• XML<br />
• Requires entry in AndroidManifest.xml (which is part of downloadable Eclipse<br />
project for Widgets)<br />
• More <strong>de</strong>tails<br />
• Co<strong>de</strong> and some information given in Spinner lecture<br />
• Even more information given in later lecture on Intents<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
OVERALL WIDGET PROJECT<br />
LAYOUT<br />
Java co<strong>de</strong><br />
Images and XML files that refer to sets of images. The<br />
layout files will refer to these images via @drawable/<br />
base_file_name (e.g., @drawable/gps). The first<br />
ImageButton example will use an image file, and the<br />
second ImageButton example will use an XML file<br />
containing references to image files.<br />
Layout files. The Java co<strong>de</strong> will refer to the overall layouts via<br />
R.layout.base_file_name (R.layout.main, R.layout.buttons, etc.). The<br />
Java co<strong>de</strong> will refer to specific GUI elements with<br />
findViewById(R.id.element_id).<br />
Strings. The Java co<strong>de</strong> will refer to these via<br />
getString(R.string.string_name). The layout files will refer to these with<br />
@string/string_name. You can also <strong>de</strong>fine arrays of strings here, or put the<br />
arrays in a separate file typically called arrays.xml. Arrays are used in the<br />
next lecture on Spinners.<br />
In or<strong>de</strong>r for one Activity to start another Activity in the same project, you need some<br />
entries in here. See Spinner lecture.
jeudi 26 janvier 12<br />
APPROACH FOR<br />
BUTTON-RELATED EXAMPLES
jeudi 26 janvier 12<br />
SUMMARY OF LAYOUT<br />
Horizontal LinearLayout (with 3 Buttons)<br />
Horizontal LinearLayout (with 3 ImageButtons)<br />
Horizontal LinearLayout (with 3 ImageButtons)<br />
Horizontal RadioGroup<br />
(with 3 RadioButtons)<br />
Horizontal RadioGroup<br />
(with 3 RadioButtons)<br />
Horizontal LinearLayout (with 3 CheckBoxes)<br />
Vertical<br />
LinearLayou<br />
Horizontal LinearLayout (with 3 ToggleButtons)<br />
An upcoming tutorial section gives <strong>de</strong>tails on using layouts. However, you can do a pretty<br />
lot now by knowing just two simple things:<br />
1) You can make some pretty complex layouts by nesting horizontal and vertical layouts<br />
insi<strong>de</strong> each other.<br />
2) You can experiment interactively with the visual layout editor in Eclipse. Edit layout file<br />
and click on Graphical Layout.<br />
t
XML: LAYOUT FILE<br />
(RES/LAYOUT/BUTTONS.XML)<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12<br />
One entry for each row in previous sli<strong>de</strong>.<br />
These entries are shown in upcoming sli<strong>de</strong>s.
XML: STRINGS FILE<br />
(RES/VALUES/STRINGS.XML)<br />
<br />
<br />
jeudi 26 janvier 12<br />
<br />
...<br />
...<br />
...<br />
<br />
<br />
<br />
JAVA (BUTTONACTIVITY.JAVA)<br />
public class ButtonActivity extends Activity {<br />
...<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.buttons);<br />
...<br />
}<br />
private void showToast(String text) {<br />
Toast.makeText(this, text, Toast.LENGTH_LONG).show();<br />
}
jeudi 26 janvier 12<br />
BUTTON
BUTTON<br />
• I<strong>de</strong>a<br />
• A push button displaying text<br />
• Main Listener type<br />
• View.OnClickListener<br />
• If you specify the handler method in the XML file, you never explicitly refer to this<br />
Listener class.<br />
• Key XML attributes<br />
• android:text<br />
• The label of the button. Can also be manipulated in Java with setText and getText<br />
• android:onClick<br />
• The event handler method. As shown in event-handling lecture, you can also use<br />
android:id and then have Java co<strong>de</strong> programmatically assign event handler.<br />
jeudi 26 janvier 12
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/BUTTONS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
<br />
XML: STRINGS FILE ENTRIES<br />
(PART OF RES/VALUES/STRINGS.XML)<br />
jeudi 26 janvier 12<br />
Hi!<br />
Bye!<br />
Yo!<br />
<br />
You clicked the \'%s\' Widget.<br />
<br />
These are the labels referred to in<br />
previous sli<strong>de</strong><br />
The event handler method will use<br />
String.format and this template to<br />
produce a message that will be<br />
shown in a Toast (short-lived<br />
popup message) when a Button is<br />
clicked.
JAVA (RELEVANT PARTS)<br />
public class ButtonActivity extends Activity {<br />
private String mButtonMessageTemplate;<br />
}<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.buttons);<br />
mButtonMessageTemplate =<br />
getString(R.string.button_message_template);<br />
}<br />
public void showButtonText(View clickedButton) {<br />
Button button = (Button)clickedButton;<br />
CharSequence text = button.getText();<br />
String message =<br />
String.format(mButtonMessageTemplate, text);<br />
showToast(message);<br />
}<br />
This is the method specified for<br />
each Button via the<br />
android:onClick attribute in the<br />
layout file.
jeudi 26 janvier 12<br />
Emulator<br />
RESULTS<br />
Phone
jeudi 26 janvier 12<br />
IMAGEBUTTON<br />
(EACH WITH SINGLE IMAGE)
IMAGEBUTTON, VARIATION 1<br />
• I<strong>de</strong>a<br />
• A push button displaying an image<br />
• Main Listener type<br />
• View.OnClickListener<br />
• Key XML attributes<br />
• android:src<br />
jeudi 26 janvier 12<br />
If you just want to display an<br />
image, but not take action when it<br />
is clicked, see the ImageView<br />
class.<br />
• The image for the button. Refers to the base name (minus the extension) of an image file<br />
in the res/drawable fol<strong>de</strong>r<br />
• Supported formats are png, jpeg, gif, and bmp.<br />
You can also refer to a drawable XML file as in next example.<br />
• The localization lecture will talk about drawable-xdpi fol<strong>de</strong>rs<br />
• Can also be set in Java with setImageDrawable<br />
• android:onClick<br />
• The event handler method
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/BUTTONS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
<br />
<br />
Refers to res/drawable/<br />
android_platform.png<br />
Refers to res/drawable/<br />
camera_phone.png<br />
Refers to res/drawable/gps.png
XML: STRINGS FILE ENTRIES<br />
(PART OF RES/VALUES/STRINGS.XML)<br />
jeudi 26 janvier 12<br />
<br />
You clicked the ImageButton that displays %s.<br />
<br />
<br />
the android_platform.png image<br />
<br />
<br />
the camera_phone.png image<br />
<br />
<br />
the gps.png image<br />
<br />
The event handler method will use<br />
String.format, this template, and<br />
the <strong>de</strong>scriptions below to produce<br />
a message that will be shown in a<br />
Toast when an ImageButton is<br />
clicked.
JAVA (RELEVANT PARTS)<br />
public class ButtonActivity extends Activity {<br />
private String mImageButtonMessageTemplate;<br />
}<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
...<br />
mImageButtonMessageTemplate =<br />
getString(R.string.image_button_message_template);<br />
}<br />
public void showImageButton1Info(View clickedImageButton) {<br />
showImageButtonInfo(R.string.image_button_1_image);<br />
}<br />
...<br />
private void showImageButtonInfo(int imageId) {<br />
String image = getString(imageId);<br />
String message =<br />
String.format(mImageButtonMessageTemplate, image);<br />
showToast(message);<br />
}<br />
This is the method specified for the first<br />
ImageButton via the android:onClick attribute in<br />
the layout file. Methods for the other<br />
ImageButtons are similar.
jeudi 26 janvier 12<br />
RESULTS (EMULATOR)
jeudi 26 janvier 12<br />
IMAGEBUTTON<br />
(EACH WITH 3 IMAGES)
IMAGEBUTTON, VARIATION 2<br />
• I<strong>de</strong>a<br />
• A push button displaying one of three images, <strong>de</strong>pending upon the situation<br />
• Main Listener type<br />
• View.OnClickListener<br />
• Key XML attributes<br />
• android:src<br />
• The image <strong>de</strong>scriptor file for the button. Refers to the base name (minus<br />
the .xml extension) of an XML file in the res/drawable fol<strong>de</strong>r<br />
• The file, in turn, refers to three regular images in drawable fol<strong>de</strong>r<br />
• Can also be set in Java with setImageDrawable<br />
• android:onClick<br />
• The event handler method<br />
jeudi 26 janvier 12
INDIVIDUAL IMAGE FILES<br />
VS. XML FILES<br />
• Individual image files<br />
• Android will use the same image for all states of the button (normal, focused,<br />
pressed)<br />
• Android will change the background color when focused or pressed. This affects<br />
the transparent pixels.<br />
To get images for practicing, look in android-sdk-installdir/platform-x/data/res/drawable-xdpi.<br />
Or, do a Google search for free icons. Also, see http://<br />
<strong>de</strong>veloper.android.com/gui<strong>de</strong>/<strong>de</strong>veloping/tools/<br />
draw9patch.html for building your own images.<br />
• XML files<br />
• Android will use a different image for each state of the button (normal, focused,<br />
pressed)<br />
• The different images can have different foreground colors, not just different<br />
backgrounds.<br />
jeudi 26 janvier 12
IMAGE DESCRIPTOR FILE (RES/<br />
DRAWABLE/BUTTON_ANDROID.XML)<br />
<br />
<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12<br />
The or<strong>de</strong>r of the three files matters. For more <strong>de</strong>tail, see http://<br />
<strong>de</strong>veloper.android.com/reference/android/widget/ImageButton.html<br />
These are the actual image files<br />
for each of the three possible<br />
states of the ImageButton.
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/BUTTONS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
<br />
<br />
Refers to res/drawable/button_android.xml. This,<br />
in turn, refers to three regular image files. Co<strong>de</strong><br />
on previous sli<strong>de</strong>.<br />
Refers to res/drawable/button_dialog.xml. This<br />
in turn, refers to three regular image files.<br />
Refers to res/drawable/button_rating_star.xml.<br />
This, in turn, refers to three regular image files
XML: STRINGS FILE ENTRIES<br />
(PART OF RES/VALUES/STRINGS.XML)<br />
jeudi 26 janvier 12<br />
<br />
You clicked the ImageButton that displays %s.<br />
<br />
<br />
the Drawable <strong>de</strong>fined in button_android.xml<br />
<br />
<br />
the Drawable <strong>de</strong>fined in button_dialog.xml<br />
<br />
<br />
the Drawable <strong>de</strong>fined in button_rating_star.xml<br />
<br />
The event handler method will use<br />
String.format, this template, and the<br />
<strong>de</strong>scriptions below to produce a<br />
message that will be shown in a Toast<br />
when an ImageButton is clicked. This<br />
is just a copy of entry already shown in<br />
previous ImageButton example.
JAVA (RELEVANT PARTS)<br />
public class ButtonActivity extends Activity {<br />
private String mImageButtonMessageTemplate;<br />
}<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
...<br />
mImageButtonMessageTemplate =<br />
getString(R.string.image_button_message_template);<br />
}<br />
public void showImageButton4Info(View clickedImageButton) {<br />
showImageButtonInfo(R.string.image_button_4_image);<br />
}<br />
...<br />
private void showImageButtonInfo(int imageId) {<br />
String image = getString(imageId);<br />
String message =<br />
String.format(mImageButtonMessageTemplate, image);<br />
showToast(message);<br />
}<br />
This is the method specified for the first of<br />
these 3 ImageButtons via the<br />
android:onClick attribute in the layout file.<br />
Methods for the other ImageButtons are<br />
similar.
jeudi 26 janvier 12<br />
RESULTS (EMULATOR)
jeudi 26 janvier 12<br />
RADIOBUTTON<br />
(WITH EVENT HANDLER ATTACHED TO<br />
EACH)
RADIOBUTTON<br />
• I<strong>de</strong>a<br />
• A button for choosing a single option among alternatives<br />
• Main Listener types<br />
• View.OnClickListener<br />
• Assign to each RadioButton if you only care about which has been pressed most<br />
recently. But also see upcoming example for Listener attached to the RadioGroup.<br />
• No need to explicitly refer to Listener when using android:onClick<br />
• No Listener at all<br />
• Some apps take no action when RadioButton is clicked, but instead query the<br />
RadioGroup later to find selection<br />
• Key XML attributes<br />
• android:text, android:onClick<br />
• Same as in previous examples.<br />
jeudi 26 janvier 12
RADIOGROUP<br />
• I<strong>de</strong>a<br />
• Similar to LinearLayout, but specifically for organizing RadioButtons.<br />
• Makes the RadioButtons exclusive (checking one causes previous selection<br />
to become unchecked)<br />
• Main Listener types<br />
• RadioGroup. OnCheckedChangeListener<br />
• Assign to RadioGroup if you want to keep track of both current and previous selections<br />
• Key XML attributes<br />
• Mostly same as for LinearLayout<br />
• Use android:id if you want to programmatically set an<br />
OnCheckedChangeListener<br />
• No android:onBlah to set RadioGroup Listener in XML<br />
jeudi 26 janvier 12
FIRST EXAMPLE: EVENT HANDLERS<br />
ATTACHED TO EACH RADIOBUTTON<br />
• I<strong>de</strong>a<br />
• Respond to clicks on each RadioButton by showing Toast<br />
saying which one was pressed.<br />
• Approach<br />
jeudi 26 janvier 12<br />
• Put RadioButtons insi<strong>de</strong> RadioGroup so that they are<br />
mutually exclusive.<br />
• To assign event handlers, use android:onClick for each<br />
RadioButton<br />
• No id for RadioGroup. No Listener for RadioGroup
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/BUTTONS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
<br />
<br />
This first example uses click<br />
handlers attached to each<br />
RadioButton.
STRINGS FILE AND JAVA<br />
• Nothing new for this example<br />
jeudi 26 janvier 12<br />
• Strings file<br />
CODE<br />
• Already showed button labels and<br />
button_message_template<br />
• Java co<strong>de</strong><br />
• Already showed makeToast and showButtonText
jeudi 26 janvier 12<br />
RESULTS (EMULATOR)
jeudi 26 janvier 12<br />
RADIOBUTTON<br />
(WITH EVENT HANDLER<br />
ATTACHED TO RADIOGROUP)
SECOND EXAMPLE: EVENT HANDLER<br />
• I<strong>de</strong>a<br />
ATTACHED TO RADIOGROUP<br />
• Respond to clicks by showing Toast saying which one was<br />
pressed and which one was previously selected.<br />
• Approach<br />
jeudi 26 janvier 12<br />
• Put RadioButtons insi<strong>de</strong> RadioGroup so that they are mutually<br />
exclusive.<br />
• Same as last example<br />
• In XML, give id to RadioGroup.<br />
• In Java, find RadioGroup and call setOnCheckedChangeListener
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/BUTTONS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
<br />
<br />
The id is nee<strong>de</strong>d so that Java can get a<br />
reference and programmatically set the<br />
OnCheckedChangeListener.<br />
RadioButtons do not have<br />
android:onClick entries
XML: STRINGS FILE ENTRIES<br />
(PART OF RES/VALUES/STRINGS.XML)<br />
jeudi 26 janvier 12<br />
<br />
You selected the \'%s\' RadioButton.<br />
There was no previous selection.<br />
<br />
<br />
You selected the \'%s\' RadioButton.<br />
Previous selection was \'%s\'.<br />
The event handler method will use String.format, one of these templates, the<br />
current selection, and the previous selection to produce a message that will be<br />
shown in a Toast when a RadioButton is clicked.<br />
Use formatted="false" if a string has more than one %s placehol<strong>de</strong>r.
JAVA (RELEVANT PARTS)<br />
public class ButtonActivity extends Activity {<br />
...<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.buttons);<br />
...<br />
RadioGroup radioGroup =<br />
(RadioGroup)findViewById(R.id.radio_group);<br />
radioGroup.setOnCheckedChangeListener(new RadioGroupInfo());<br />
}<br />
Continued on next page.<br />
RadioGroupInfo is an inner class insi<strong>de</strong><br />
ButtonActivity.
JAVA<br />
(RELEVANT PARTS, CONTINUED)<br />
private class RadioGroupInfo implements OnCheckedChangeListener {<br />
private RadioButton mLastChecked;<br />
private String mNewSelectionMessageTemplate;<br />
private String mChangedSelectionMessageTemplate;<br />
jeudi 26 janvier 12<br />
public RadioGroupInfo() {<br />
mNewSelectionMessageTemplate =<br />
getString(R.string.new_selection_message_template);<br />
mChangedSelectionMessageTemplate =<br />
getString(R.string.changed_selection_message_template);<br />
}<br />
Top of the inner class
JAVA<br />
(RELEVANT PARTS, CONTINUED)<br />
}<br />
}<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCheckedChanged(RadioGroup group, int checkedId) {<br />
RadioButton newChecked =<br />
(RadioButton)findViewById(checkedId);<br />
String message;<br />
if (mLastChecked == null) { // No previous selection<br />
message = String.format(mNewSelectionMessageTemplate,<br />
newChecked.getText());<br />
} else {<br />
message = String.format(mChangedSelectionMessageTemplate,<br />
newChecked.getText(),<br />
mLastChecked.getText());<br />
}<br />
mLastChecked = newChecked;<br />
showToast(message);<br />
}<br />
Bottom of the inner class. Keeps track of current<br />
and previous selections.
jeudi 26 janvier 12<br />
RESULTS (EMULATOR)
jeudi 26 janvier 12<br />
CHECKBOX
CHECKBOX<br />
• I<strong>de</strong>a<br />
• A button with two states (checked and unchecked)<br />
• Has visual indicator to show whether it is checked<br />
• In Java, use isChecked() to <strong>de</strong>termine state. Use setChecked to<br />
programmatically change the state.<br />
• Same text in both states (unlike ToggleButton)<br />
• Main Listener types<br />
• View.OnClickListener<br />
• No Listener at all<br />
• Take no action when CheckBox is clicked, but instead query the CheckBox<br />
later to find if it is checked or not<br />
• Key XML attributes<br />
• android:text, android:onClick<br />
• Same as in previous examples<br />
jeudi 26 janvier 12
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/BUTTONS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
<br />
<br />
Note that the class name is CheckBox, not<br />
Checkbox<br />
(as in AWT).
STRINGS FILE AND JAVA<br />
• Nothing new for this example<br />
jeudi 26 janvier 12<br />
• Strings file<br />
CODE<br />
• Already showed button labels and<br />
button_message_template<br />
• Java co<strong>de</strong><br />
• Already showed makeToast and showButtonText
jeudi 26 janvier 12<br />
RESULTS (EMULATOR)
jeudi 26 janvier 12<br />
TOGGLEBUTTON
TOGGLEBUTTON<br />
• I<strong>de</strong>a<br />
• A button with two states (checked and unchecked)<br />
• Has visual indicator to show whether it is checked<br />
• In Java, use isChecked() to <strong>de</strong>termine state. Use setChecked to programmatically change the state.<br />
• Has different text for each state (unlike CheckBox)<br />
• Main Listener types<br />
• View.OnClickListener<br />
• No Listener at all<br />
• Take no action when ToggleButton is clicked, but instead query the ToggleButton later to find if it is<br />
checked or not<br />
• Key XML attributes<br />
• android:textOn, android:textOff<br />
• The text for the two states. If you omit this, then the text is automatically ON and OFF (in caps)<br />
• android:onClick<br />
• Same as in previous examples<br />
jeudi 26 janvier 12
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/BUTTONS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
<br />
<br />
No textOn or textOff attributes, so the<br />
<strong>de</strong>faults of ON and OFF will be used.
XML: STRINGS FILE ENTRIES<br />
(PART OF RES/VALUES/STRINGS.XML)<br />
jeudi 26 janvier 12<br />
Use SSL<br />
No SSL<br />
GPS On<br />
GPS Off<br />
<br />
You turned the ToggleButton %s.<br />
Label is now \'%s\'.<br />
<br />
The event handler method will use<br />
String.format, this template, the<br />
state of the ToggleButton (on or<br />
off), and the text to produce a<br />
message that will be shown in a<br />
Toast when a ToggleButton is<br />
clicked.
JAVA (RELEVANT PARTS)<br />
public class ButtonActivity extends Activity {<br />
private String mToggleButtonMessageTemplate;<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
...<br />
mToggleButtonMessageTemplate =<br />
getString(R.string.toggle_button_message_template);<br />
}
JAVA<br />
(RELEVANT PARTS, CONTINUED)<br />
This is the method specified for the<br />
jeudi 26 janvier 12<br />
public void showToggleButtonInfo(View clickedToggleButton) {<br />
ToggleButton toggleButton =<br />
(ToggleButton)clickedToggleButton;<br />
String status;<br />
if (toggleButton.isChecked()) {<br />
status = "ON";<br />
} else {<br />
status = "OFF";<br />
}<br />
CharSequence label = toggleButton.getText();<br />
String message =<br />
String.format(mToggleButtonMessageTemplate,<br />
status, label);<br />
showToast(message);<br />
}<br />
ToggleButtons via the android:onClick attribute in<br />
the layout file.
jeudi 26 janvier 12<br />
RESULTS (EMULATOR)
jeudi 26 janvier 12<br />
WRAP-UP
SUMMARY<br />
• Click handling is consistent among buttons<br />
• Button, ImageButton, RadioButton, CheckBox, ToggleButton<br />
• Can specify event handler method with android:onClick<br />
• Or can set programmatically as in events lecture<br />
• ImageButton<br />
• Can have single image or set of three.<br />
• Specify with android:src<br />
• Images and image XML files go in res/drawable fol<strong>de</strong>r<br />
• RadioGroup<br />
• Surrounds RadioButtons. Can have its own Listener if you need to track previous<br />
selection.<br />
• ToggleButton<br />
• Similar behavior to CheckBox. But has android:textOn and android:textOff instead of a<br />
fixed label.<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
WIDGETS: SPINNERS<br />
(COMBO BOXES)<br />
<strong>David</strong> <strong>Defour</strong><br />
<strong>Université</strong> <strong>de</strong> <strong>Perpignan</strong><br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/
TOPICS IN THIS SECTION<br />
• Switching from one Activity to another<br />
• Spinners with choices set in XML<br />
• Spinners with choices set in Java<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
GENERAL APPROACH<br />
FOR WIDGET EXAMPLES
WIDGET LECTURES COMBINED<br />
IN SINGLE PROJECT<br />
• Main screen<br />
• Lets user choose screens on various Widget topics<br />
• Other screens<br />
• Correspond to separate lectures.<br />
• One screen for lecture on Buttons, another for lecture on Spinners, another for<br />
number input, etc.<br />
• Separate layout files<br />
• main.xml, buttons.xml, spinners.xml, etc. See next sli<strong>de</strong>.<br />
• Separate Java classes<br />
• WidgetActivity.java, ButtonActivity.java, SpinnerActivity.java, etc.<br />
• Shared strings file<br />
• strings.xml has separate sections for each lecture, but same file<br />
jeudi 26 janvier 12
LAYOUT FILES FOR WIDGET<br />
LECTURES<br />
• Separate layout files for each Activity<br />
• res/layout/main.xml<br />
• Gives layout for main screen. Loa<strong>de</strong>d with setContentView(R.layout.main);<br />
• res/layout/buttons.xml<br />
• Gives layout for screen on Button and related Widgets. Loa<strong>de</strong>d with<br />
setContentView(R.layout.buttons);<br />
• res/layout/spinners.xml<br />
• Gives layout for screen on Spinners (i.e., combo boxes). Loa<strong>de</strong>d with<br />
setContentView(R.layout.spinners);<br />
• Two common layout attributes<br />
• android:layout_width, android:layout_height<br />
• match_parent (fill up space in enclosing View)<br />
• wrap_content (use natural size)<br />
jeudi 26 janvier 12
STRINGS FILE FOR WIDGET LECTURES<br />
(RES/VALUES/STRINGS.XML)<br />
<br />
<br />
<br />
...<br />
...<br />
...<br />
<br />
<br />
<br />
<br />
...<br />
<br />
jeudi 26 janvier 12
SWITCHING ACTIVITIES:<br />
SUMMARY<br />
• Switches Activities with Intents<br />
• Main screen has buttons to navigate to other Activities<br />
• Return to original screen with phone’s “back” button<br />
• Syntax required to start new Activity<br />
• Java<br />
• Intent newActivity = new Intent(this, NewActivity.class);<br />
• startActivity(newActivity);<br />
• XML<br />
• Requires entry in AndroidManifest.xml (which is part of downloadable Eclipse<br />
project for Widgets)<br />
• More <strong>de</strong>tails<br />
• Co<strong>de</strong> shown on next few sli<strong>de</strong>s<br />
• Even more information given in later lecture on Intents<br />
jeudi 26 janvier 12
SWITCHING ACTIVITIES:<br />
DETAILS<br />
• Java (InitialActivity.java)<br />
Intent newActivity = new Intent(this, NewActivity.class);<br />
startActivity(newActivity);<br />
• XML (AndroidManifest.xml)<br />
<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
<br />
SWITCHING ACTIVITIES:<br />
WIDGETSINITIALACTIVITY.JAVA<br />
public class WidgetsInitialActivity extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
}<br />
}<br />
private void goToActivity<br />
(Class
SWITCHING ACTIVITIES:<br />
ANDROIDMANIFEST.XML<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Most parts of this file were created automatically when the Android<br />
project was ma<strong>de</strong> in Eclipse. To switch Activities yourself, cut and paste<br />
this co<strong>de</strong> from the downloadable source, and change only android:name<br />
and android:label.<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
OVERALL WIDGET PROJECT<br />
LAYOUT<br />
Java co<strong>de</strong><br />
Images and XML files that refer to sets of images. The<br />
layout files will refer to these images via @drawable/<br />
base_file_name (e.g., @drawable/gps). See ImageButton<br />
examples in lecture on buttons.<br />
Layout files. The Java co<strong>de</strong> will refer to the overall layouts via<br />
R.layout.base_file_name (R.layout.main, R.layout.spinners, etc.). The<br />
Java co<strong>de</strong> will refer to specific GUI elements with<br />
findViewById(R.id.element_id).<br />
Strings. The Java co<strong>de</strong> will refer to these via<br />
getString(R.string.string_name). The layout files will refer to these with<br />
@string/string_name. You can also <strong>de</strong>fine arrays of strings here, or put the<br />
arrays in a separate file typically called arrays.xml. Arrays <strong>de</strong>fined here are<br />
used in the first Spinner example.<br />
In or<strong>de</strong>r for one Activity to start another Activity in the same project, you need some<br />
entries in here. See upcoming sli<strong>de</strong>.
jeudi 26 janvier 12<br />
SPINNER APPROACH 1:<br />
CHOICES SPECIFIED IN XML
SPINNER WITH PREDEFINED<br />
• I<strong>de</strong>a<br />
CHOICES<br />
• A combo box (drop down list of choices)<br />
• Similar purpose to a RadioGroup: to let the user choose<br />
among a fixed set of options<br />
• Main Listener types<br />
jeudi 26 janvier 12<br />
• AdapterView.OnItemSelectedListener<br />
• AdapterView.OnItemClickedListener<br />
• The first is more general purpose, since it will be invoked on<br />
programmatic changes and keyboard events as well as clicks.
SPINNER (CONTINUED)<br />
• Key XML attributes<br />
• android:id<br />
• You need a Java reference to assign an event handler<br />
• android:prompt<br />
• The text shown at the top of Spinner when user clicks to open it.<br />
• Since text is not shown when the Spinner is closed, the string used for the prompt is typically also displayed in a<br />
TextView above the Spinner.<br />
• android:entries<br />
• An XML entry <strong>de</strong>fining an array of choices.<br />
Can be in strings.xml or a separate file (e.g., arrays.xml)<br />
<br />
choice 1<br />
choice 2<br />
…<br />
<br />
jeudi 26 janvier 12
ONITEMSELECTEDLISTENER<br />
• onItemSelected<br />
• Invoked when the an entry is selected. Invoked once when Spinner is first<br />
displayed, then again for each time the user selects something.<br />
• Arguments<br />
• AdapterView: the Spinner itself<br />
• View: the row of the Spinner that was selected<br />
• int: the in<strong>de</strong>x of the selection. Pass this to the Spinner’s getItemAtPosition<br />
method to get the text of the selection.<br />
• long: The row id of the selected item<br />
• onNothingSelected<br />
• Invoked when there is now nothing displayed. This cannot happen due to<br />
normal user interaction, but only when you programmatically remove an entry.<br />
jeudi 26 janvier 12
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/SPINNERS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
Same text used twice, since<br />
the text is hid<strong>de</strong>n when the<br />
Spinner is closed.<br />
An array of entries. If you have<br />
lots of arrays, you typically put<br />
them in arrays.xml. However,<br />
here, it makes more sense to<br />
keep the array of entries in<br />
strings.xml with the spinner<br />
prompt and the spinner<br />
message template.
XML: STRINGS FILE ENTRIES<br />
(PART OF RES/VALUES/STRINGS.XML)<br />
jeudi 26 janvier 12<br />
<br />
Current Android Vendors (Choices from XML)<br />
<br />
<br />
Acer<br />
Dell<br />
HTC<br />
Huawei<br />
Kyocera<br />
LG<br />
Motorola<br />
Nexus<br />
Samsung<br />
Sony Ericsson<br />
T-Mobile<br />
Neptune<br />
<br />
<br />
You selected \'%s\'.<br />
<br />
The event handler method will use<br />
String.format, this template, and<br />
the current selection to produce a<br />
message that will be shown in a<br />
Toast when a Spinner selection is<br />
ma<strong>de</strong>.
JAVA (RELEVANT PARTS)<br />
public class SpinnerActivity extends Activity {<br />
private String mItemSelectedMessageTemplate;<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.spinners);<br />
mItemSelectedMessageTemplate =<br />
getString(R.string.spinner_message_template);<br />
Spinner spinner1 = (Spinner)findViewById(R.id.spinner1);<br />
spinner1.setOnItemSelectedListener(new SpinnerInfo());<br />
... // Co<strong>de</strong> for spinner2 shown later<br />
}<br />
private void showToast(String text) {<br />
Toast.makeText(this, text, Toast.LENGTH_LONG).show();<br />
}<br />
// Continued on next sli<strong>de</strong> with the SpinnerInfo inner class
JAVA<br />
(RELEVANT PARTS, CONTINUED)<br />
private class SpinnerInfo implements OnItemSelectedListener {<br />
private boolean isFirst = true;<br />
}<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
Don't want the Toast when the screen is first displayed,<br />
public void onItemSelected(AdapterView so ignore spinner, the first call to View onItemSelected. selectedView,<br />
Other calls are<br />
int selectedIn<strong>de</strong>x, long due to user id) interaction. {<br />
if (isFirst) {<br />
isFirst = false;<br />
} else {<br />
String selection =<br />
spinner.getItemAtPosition(selectedIn<strong>de</strong>x).toString();<br />
String message =<br />
String.format(mItemSelectedMessageTemplate, selection);<br />
showToast(message);<br />
}<br />
}<br />
@Overri<strong>de</strong><br />
public void onNothingSelected(AdapterView spinner) {<br />
// Won’t be invoked unless you programmatically remove entries<br />
}
jeudi 26 janvier 12<br />
RESULTS (EMULATOR)
jeudi 26 janvier 12<br />
SPINNER APPROACH 2:<br />
CHOICES SPECIFIED IN JAVA
SPINNER WITH CHOICES<br />
COMPUTED BY JAVA CODE<br />
• I<strong>de</strong>a<br />
• A combo box (drop down list of choices)<br />
• Same general purpose as previous example. However, here you<br />
want to programmatically compute the options to be displayed,<br />
possibly based on earlier user interaction.<br />
• Main Listener types<br />
• AdapterView.OnItemSelectedListener<br />
• AdapterView.OnItemClickedListener<br />
jeudi 26 janvier 12<br />
• These are same as in previous Spinner example
SPINNER (CONTINUED)<br />
• Key XML attributes<br />
• android:id<br />
• You need a Java reference to specify the entries and to assign an event<br />
handler.<br />
• android:prompt<br />
• The text shown at the top of Spinner when user clicks to open it.<br />
• Since this text is not shown when the Spinner is closed, the string<br />
used for the prompt is typically also displayed in a TextView above<br />
the Spinner.<br />
• android:entries<br />
• Not used in this version. Java will compute the entries.<br />
jeudi 26 janvier 12
CREATING SPINNER ENTRIES<br />
PROGRAMMATICALLY<br />
• Get reference to the Spinner<br />
Spinner spinner = (Spinner)findViewById(R.id.spinner_id);<br />
• Make an ArrayAdapter<br />
List entries = …; // Can also use String[]<br />
ArrayAdapter spinnerAdapter =<br />
new ArrayAdapter(this,<br />
android.R.layout.simple_spinner_item,<br />
entries);<br />
• Specify the drop down View resource<br />
spinnerAdapter.setDropDownViewResource<br />
(android.R.layout.simple_spinner_dropdown_item);<br />
• Set the adapter for the Spinner<br />
spinner.setAdapter(spinnerAdapter);<br />
jeudi 26 janvier 12<br />
Pre<strong>de</strong>fined entry in<br />
Android distribution
XML: LAYOUT FILE ENTRY<br />
(PART OF RES/LAYOUT/SPINNERS.XML)<br />
jeudi 26 janvier 12<br />
<br />
<br />
Same text used twice, since<br />
the text is hid<strong>de</strong>n when the<br />
Spinner is closed.<br />
android:entries is not used.<br />
Instead of having fixed<br />
choices, the Java co<strong>de</strong> will<br />
compute the options.
XML: STRINGS FILE ENTRIES<br />
(PART OF RES/VALUES/STRINGS.XML)<br />
jeudi 26 janvier 12<br />
<br />
Future Android Vendors (Choices from Java)<br />
JAVA (RELEVANT PARTS)<br />
public class SpinnerActivity extends Activity {<br />
private String mItemSelectedMessageTemplate;<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
// General co<strong>de</strong> and co<strong>de</strong> for spinner1 shown earlier<br />
List futureAndroidVendors =<br />
getFutureAndroidVendors();<br />
ArrayAdapter spinner2Adapter =<br />
new ArrayAdapter(this,<br />
android.R.layout.simple_spinner_item,<br />
futureAndroidVendors);<br />
spinner2Adapter.setDropDownViewResource<br />
(android.R.layout.simple_spinner_dropdown_item);<br />
spinner2.setAdapter(spinner2Adapter);<br />
spinner2.setOnItemSelectedListener(new SpinnerInfo());<br />
}
JAVA<br />
(RELEVANT PARTS, CONTINUED)<br />
jeudi 26 janvier 12<br />
private List getFutureAndroidVendors() {<br />
String[] vendorArray = { "Apple", "RIM",<br />
"Palm", "Microsoft" };<br />
List vendorList = Arrays.asList(vendorArray);<br />
Collections.shuffle(vendorList);<br />
return(vendorList);<br />
} The last argument to the ArrayAdapter<br />
constructor on previous page can be any List<br />
or String[]. I am randomizing the or<strong>de</strong>r of the<br />
elements to <strong>de</strong>monstrate that you can have Java<br />
compute the entries instead of having a fixed set of<br />
choiuces (in which case you would <strong>de</strong>fine the entries<br />
in the XML file as with approach 1).
jeudi 26 janvier 12<br />
RESULTS (EMULATOR)
jeudi 26 janvier 12<br />
WRAP-UP
SUMMARY<br />
• Spinner with fixed entries<br />
• Define array in strings.xml.<br />
• Use android:prompt and android:entries in layout file. Also assign id with<br />
android:id<br />
• Java gets ref and calls setOnItemSelectedListener<br />
• Spinner with computed entries<br />
• XML uses android:prompt and android:id<br />
• Java gets ref, makes ArrayAdapter with a List or String[], uses some<br />
pre<strong>de</strong>fined resource names<br />
• Switching Activities<br />
• Intent newActivity = new Intent(this, NewActivity.class);<br />
• startActivity(newActivity);<br />
• Also requires entry in AndroidManifest.xml<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Layouts:<br />
Organizing the Screen<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• LinearLayout<br />
• Strategy of nesting layouts<br />
• Using color files<br />
–And preview of Localization<br />
• Layout weights<br />
• RelativeLayout<br />
• TableLayout<br />
• hierarchyviewer<br />
261<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Main Layout Strategies<br />
• XML-based<br />
– Declare layout in res/layouts/some_layout.xml<br />
• Set various XML properties<br />
• Use visual editor in Eclipse<br />
– Load with setContentView(R.layout.some_layout)<br />
• Java-based<br />
– Instantiate layout, set properties, insert sub-layouts<br />
• LinearLayout window = new LinearLayout(this);<br />
• window.setVariousAttributes(…);<br />
• window.addView(widgetOrLayout);<br />
– Load with setContentView(window)<br />
• This tutorial<br />
– Uses XML-based approach. However, attributes can be adapted<br />
for Java-based approach.<br />
263<br />
jeudi 26 janvier 12
XML Layout Attributes<br />
• I<strong>de</strong>a<br />
– Each Layout class has an inner class called LayoutParams that<br />
<strong>de</strong>fines general XML parameters that layout uses. These<br />
parameters are always named android:layout_blah, and usually<br />
have to do with sizes and margins.<br />
– Layout classes <strong>de</strong>fine more specific attributes. Many inherited<br />
from LinearLayout (which extends ViewGroup and View).<br />
• Not named beginning with “layout_”<br />
• Example<br />
…<br />
264<br />
jeudi 26 janvier 12
Commonly Used Attributes<br />
• Size<br />
– android:layout_height, android:layout_width<br />
• match_parent: fill the parent space (minus padding)<br />
– Renamed from fill_parent in ol<strong>de</strong>r versions<br />
• wrap_content: use natural size (plus padding)<br />
• An explicit size with a number and a dimension. See margins on next sli<strong>de</strong>.<br />
– android:layout_weight<br />
• A number that gives proportional sizes. See example.<br />
• Alignment<br />
– android:layout_gravity<br />
• How the View is aligned within containing View.<br />
– android:gravity<br />
• How the text or components insi<strong>de</strong> the View are aligned.<br />
– Possible values<br />
• top, bottom, left, right, center_vertical, center_horizontal, center (i.e., center both<br />
ways), fill_vertical, fill_horizontal, fill (i.e., fill both directions), clip_vertical,<br />
clip_horizontal<br />
265<br />
jeudi 26 janvier 12
Commonly Used Attributes<br />
(Continued)<br />
• Margins (blank space outsi<strong>de</strong>)<br />
–android:layout_marginBottom, android:layout_marginTop,<br />
android:layout_marginLeft, android:layout_marginRight<br />
–Units (e.g., "14.5dp") – negative values are legal<br />
• dp: <strong>de</strong>nsity-in<strong>de</strong>pen<strong>de</strong>nt pixels (scaled by <strong>de</strong>vice resol.)<br />
• sp: scaled pixels (scaled based on preferred font size)<br />
• px: pixels<br />
• in: inches<br />
• mm: millimeters<br />
• Padding (blank space insi<strong>de</strong>)<br />
266<br />
jeudi 26 janvier 12<br />
–android:paddingBottom, android:paddingTop,<br />
android:paddingLeft, android:paddingRight<br />
• Values are numbers with units as above
Commonly Used Attributes<br />
(Continued)<br />
• ID<br />
–android:id<br />
• Used if the Java co<strong>de</strong> needs a reference to View<br />
• Used in RelativeLayout so XML can refer to earlier ids<br />
• Colors<br />
–android:background (color or image, for any Layout)<br />
–android:textColor (e.g., for TextView or Button)<br />
–Common color value formats<br />
• "#rrggbb", "#aarrggbb", "@color/color_name"<br />
• Click handler<br />
267<br />
jeudi 26 janvier 12<br />
–android:onClick<br />
• Should be a public method in main Activity that takes a View (the<br />
thing clicked) as argument and returns void
jeudi 26 janvier 12<br />
LinearLayout Basics<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
LinearLayout<br />
• I<strong>de</strong>a<br />
–Put components in a single row or single column<br />
–By nesting, can have rows within columns, etc.<br />
• Most important XML attributes<br />
269<br />
jeudi 26 janvier 12<br />
–android:orientation<br />
• "horizontal" (a row) or "vertical" (a column)<br />
• horizontal is the <strong>de</strong>fault, so can be omitted for rows<br />
–android:gravity<br />
• How the Views insi<strong>de</strong> are aligned.<br />
• Possible values<br />
– top, bottom, left, right, center_vertical, center_horizontal, center (i.e., center<br />
both ways), fill_vertical, fill_horizontal, fill (i.e., fill both directions), clip_vertical,<br />
clip_horizontal
Example Summary<br />
(Highly Nested Layouts)<br />
270<br />
jeudi 26 janvier 12<br />
• General Approach<br />
<br />
<br />
<br />
Example Details<br />
271<br />
jeudi 26 janvier 12<br />
Horizontal LinearLayout with gravity of center_horizontal.<br />
<br />
<br />
<br />
<br />
<br />
<br />
Horizontal LinearLayout with gravity of left. Otherwise almost<br />
same as first row.<br />
Remember that horizontal is the <strong>de</strong>fault for android:orientation, so this attribute was omitted for these<br />
two rows. The colors will be explained later in this tutorial.
Example Details<br />
272<br />
jeudi 26 janvier 12<br />
Horizontal LinearLayout.<br />
That Layout then contains two more horizontal LinearLayouts. The first<br />
(yellow) has android:layout_width of "wrap_content" and android:gravity<br />
of "left". The second (green) has android:layout_width of "match_parent"<br />
and android:gravity of "right".
Example Details<br />
273<br />
jeudi 26 janvier 12<br />
Horizontal LinearLayout.<br />
That Layout then contains three vertical nested layouts. The first (blue) is a<br />
LinearLayout with android:orientation of "vertical" and four Buttons insi<strong>de</strong>.<br />
The second (violet) is a RadioGroup (similar to LinearLayout but specific to<br />
enclosing RadioButtons and making them mutually exclusive), also with<br />
android:orientation of "vertical". It has four RadioButtons insi<strong>de</strong>. The third is<br />
a LinearLayout with android:orientation of "vertical" and four nested<br />
LinearLayouts insi<strong>de</strong> (<strong>de</strong>tails on next sli<strong>de</strong>).<br />
The first two columns (nested layouts) have android:layout_width of<br />
"wrap_content", and the third has android:layout_width of "match_parent".
Example Details<br />
274<br />
jeudi 26 janvier 12<br />
Vertical LinearLayout.<br />
That Layout then contains four horizontal nested layouts. The first (red)<br />
has android:gravity of "center_horizontal". The second (orange) has<br />
android:gravity of "left". The third (yellow) has android:gravity of "right".<br />
The fourth contains two further nested horizontal LinearLayouts. The first<br />
(green) has android:layout_width of "wrap_content" and android:gravity of<br />
"left". The second (blue) has android:layout_width of "match_parent" and<br />
android:gravity of "right".
Example Details<br />
275<br />
jeudi 26 janvier 12<br />
Button<br />
android:layout_width="wrap_content"<br />
android:layout_gravity="center_horizontal"<br />
android:layout_marginTop="20dp"<br />
Button<br />
android:layout_width="match_parent"
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Setting Colors<br />
(& Localization Preview)<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Colors<br />
• I<strong>de</strong>a<br />
– Although colors can be <strong>de</strong>fined explicitly within layout file (e.g.,<br />
background="#ff0000"), usually more flexible to <strong>de</strong>fine color<br />
names in separate file, so they can be changed all at once. Refer<br />
to color with "@color/color_name".<br />
• Syntax<br />
<br />
#rrggbb<br />
… <br />
<br />
• Convention<br />
– Use res/values/colors.xml<br />
• However, any file name is legal. Sometimes it makes more sense to<br />
<strong>de</strong>fine all attributes (strings, arrays, colors) of a View in a single file<br />
<strong>de</strong>dicated to that view.<br />
277<br />
jeudi 26 janvier 12
Color File<br />
(res/values/colors.xml)<br />
<br />
<br />
#ff0000<br />
#ffa500<br />
#ffff00<br />
#008000<br />
#0000ff<br />
#ee82ee<br />
<br />
278<br />
jeudi 26 janvier 12
Layout File (res/layouts/<br />
nested_layouts.xml)<br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
279<br />
jeudi 26 janvier 12
Result<br />
280<br />
jeudi 26 janvier 12
Localization Preview<br />
• I<strong>de</strong>a<br />
–You can store colors or other files in res/values-xy instead of<br />
res/values. If the Locale is set to xy, then that file is loa<strong>de</strong>d<br />
after the files in res/values.<br />
• If names match, later file overri<strong>de</strong>s value from earlier file<br />
• Usual approach<br />
–Locale is set for entire phone by end user<br />
• Approach used here<br />
–Locale is set programmatically<br />
• Many more <strong>de</strong>tails<br />
281<br />
jeudi 26 janvier 12<br />
–In later lecture on localization
Setting Locale Programmatically<br />
• Usual purpose<br />
–If user sometimes wants to run app in one language and other<br />
times in a different language.<br />
• Again, more common for end user to set Locale for entire phone,<br />
not for individual apps.<br />
• Purpose here<br />
282<br />
jeudi 26 janvier 12<br />
–Set the Locale to a fake value ("qq") just so that we can<br />
replace colors.xml with another version that makes all the<br />
background colors be black.
Setting Locale Programmatically<br />
• Steps<br />
Locale locale = new Locale("es"); // Language co<strong>de</strong><br />
Locale.setDefault(locale);<br />
Configuration config = new Configuration();<br />
config.locale = locale;<br />
context.getResources().updateConfiguration(config,<br />
–context above is reference to the main Activity<br />
• More <strong>de</strong>tails<br />
283<br />
jeudi 26 janvier 12<br />
–http://adrianvintu.com/blogengine/post/<br />
Force-Locale-on-Android.aspx<br />
null);
Project Layout<br />
284<br />
jeudi 26 janvier 12<br />
Sets color_1, color_2, …, color_6 to red, orange, yellow,<br />
green, blue, and violet. Full text of this file shown on<br />
earlier sli<strong>de</strong>. Used if Locale is anything other than "qq".<br />
Sets all of color_1, color_2, …, color_6 to black. Full text<br />
of this file shown on next sli<strong>de</strong>. Used only if Locale is<br />
"qq".
Localized Color File<br />
(res/values-qq/colors.xml)<br />
<br />
<br />
#000000<br />
#000000<br />
#000000<br />
#000000<br />
#000000<br />
#000000<br />
<br />
285<br />
jeudi 26 janvier 12
Main Java Co<strong>de</strong><br />
public class NestedLayoutsActivity extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.nested_layouts);<br />
}<br />
}<br />
286<br />
jeudi 26 janvier 12<br />
...<br />
// Event handlers for bottom two Buttons<br />
There are two buttons on initial screen that invoke this same<br />
Activity. But, one sets the Locale to "qq" first.
Results<br />
287<br />
jeudi 26 janvier 12<br />
Locale set to anything<br />
other than "qq".<br />
Locale set to "qq".
jeudi 26 janvier 12<br />
Layout Weight<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Using android:layout_weight<br />
• I<strong>de</strong>a<br />
– Assign numbers for android:layout_weight. Sizes given are<br />
proportional to those values.<br />
• Steps (for heights)<br />
– Assign android:layout_height to 0dp<br />
– Use relative values for android:layout_weight<br />
• For example, if you have three nested entries with<br />
android:layout_weights of 1, 1, and 2, then they take up 25%, 25%,<br />
and 50% of the height of the parent.<br />
– Analogous approach to set widths<br />
• Common strategy<br />
– Make the layout weights add up to 100, then treat them as<br />
percents. So, use 25, 25, and 50 instead of 1, 1, and 2 in the<br />
previous example. (Same effect, but clearer.)<br />
289<br />
jeudi 26 janvier 12
Layout File (res/layouts/<br />
layout_weights.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
290<br />
jeudi 26 janvier 12
Java Co<strong>de</strong><br />
public class LayoutWeightsActivity extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.layout_weights);<br />
}<br />
}<br />
291<br />
jeudi 26 janvier 12
Results<br />
292<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
RelativeLayout<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
RelativeLayout<br />
• I<strong>de</strong>a<br />
– Give ids to 1 or more key components (id="@+id/blah")<br />
– Position other components relative to those components<br />
• Most important XML attributes<br />
– Aligning with container<br />
• android:layout_alignParentBottom (and Top, Right, Left)<br />
• android:layout_centerInParent (and centerHorizontal, centerVertical)<br />
294<br />
jeudi 26 janvier 12<br />
– These all take "true" or "false" as values<br />
– Aligning with other component<br />
• android:layout_alignBottom (and Top, Right, Left)<br />
• android:layout_toLeftOf (and toRightOf), android:layout_above (and<br />
below)<br />
– These all take existing ids as values<br />
» android:layout_alignBlah="@id/existing_id" (@id, not @+id)
Referring to Existing IDs<br />
• First component<br />
–<br />
• Second component<br />
–<br />
• Result<br />
295<br />
jeudi 26 janvier 12<br />
Button 2<br />
@+id for assigning a new id<br />
Button 1<br />
@id (no +) for referring to an existing id
Example Summary<br />
296<br />
jeudi 26 janvier 12<br />
• General Approach<br />
<br />
<br />
<br />
Example Details<br />
297<br />
jeudi 26 janvier 12<br />
TextView with width of match_parent and specific height. Goes<br />
at top since I didn't say otherwise. Has id.<br />
TextView with android:layout_alignTop referring to first<br />
component. Moved down via android:layout_marginTop<br />
<br />
Example Details<br />
298<br />
jeudi 26 janvier 12<br />
<br />
<br />
<br />
EditText with android:layout_above referring to image button.<br />
Has width of match_parent.<br />
Button with android:layout_alignBottom and android:layout_toLeftOf referring to<br />
image button. Has width of wrap_content.<br />
Button with android:layout_alignParentBottom="true" and<br />
android:layout_alignParentRight="true". Has an id. Has width of wrap_content.<br />
This is the first Button <strong>de</strong>fined.
jeudi 26 janvier 12<br />
TableLayout<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
TableLayout<br />
• I<strong>de</strong>a<br />
– Put widgets or nested layouts in a grid. No bor<strong>de</strong>rs.<br />
– Like HTML tables, the number of rows and columns is<br />
<strong>de</strong>termined automatically, not explicitly specified.<br />
– Components are usually placed insi<strong>de</strong> TableRow<br />
• Most important XML attributes (TableLayout)<br />
– android:stretchColumns<br />
• An in<strong>de</strong>x or comma-separated list of in<strong>de</strong>xes. Specifies the column or<br />
columns that should be stretched wi<strong>de</strong>r if the table is narrower than its<br />
parent. In<strong>de</strong>xes are 0-based.<br />
– android:shrinkColumns<br />
• Column(s) that should be shrunk if table is wi<strong>de</strong>r than parent.<br />
– android:collapseColumns<br />
• Column(s) to be totally left out. Can be programmatically put back in<br />
later.<br />
300<br />
jeudi 26 janvier 12
TableRow<br />
• I<strong>de</strong>a<br />
– Goes insi<strong>de</strong> TableLayout to <strong>de</strong>fine a row.<br />
• Technically, elements between rows are permitted, but you can<br />
achieve same effect with a TableRow and android:layout_span.<br />
• Most important XML attributes of elements insi<strong>de</strong> a<br />
TableRow<br />
– android:layout_column<br />
• Normally, elements are placed in left-to-right or<strong>de</strong>r. However, you can<br />
use android:layout_column to specify an exact column, and thus<br />
leave earlier columns empty.<br />
– android:layout_span<br />
• The number of columns the element should straddle.<br />
Like colspan for HTML tables.<br />
• There is nothing equivalent to HTML’s rowspan; you must use nested<br />
tables instead. See example.<br />
301<br />
jeudi 26 janvier 12
Example Summary<br />
302<br />
jeudi 26 janvier 12<br />
• General Approach<br />
<br />
<br />
…<br />
…<br />
…<br />
…<br />
<br />
This is why the middle column<br />
is wi<strong>de</strong>r than the other two<br />
columns.
Example Details<br />
303<br />
jeudi 26 janvier 12<br />
Two TableRows, each with 3 Buttons. No special options.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Example Details<br />
304<br />
jeudi 26 janvier 12<br />
Button 7 uses android:layout_column="2". So, there is no entry<br />
at all for the middle column.<br />
Button 9 uses android:layout_span="2".<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Example Details<br />
305<br />
jeudi 26 janvier 12<br />
A nested table. Uses android:layout_span="2" so that it straddles two<br />
columns of the main table. Uses android:stretchColumns="1" so that the<br />
second column fills available space.<br />
A Button. android:layout_height is match_parent so that it is the same height<br />
as table to its left. There is no option similar to HTML’s colspan, so nested<br />
tables are nee<strong>de</strong>d to achieve this effect.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12<br />
The Hierarchy Viewer<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Hierarchy Viewer<br />
• I<strong>de</strong>a<br />
–The Android distribution inclu<strong>de</strong>s a program called<br />
hieararchyviewer that will show a graphical representation of<br />
Views and sub-Views. Useful for <strong>de</strong>bugging and<br />
un<strong>de</strong>rstanding nested layouts.<br />
• Details<br />
307<br />
jeudi 26 janvier 12<br />
–Start app in emulator. Go to screen of interest.<br />
–Go to android-sdk/tools (or, put this in your PATH)<br />
–Type hierarchyviewer<br />
–Click on Focused Window,<br />
then press Load View<br />
Hierarchy button<br />
–Explore!
Hierarchy View for<br />
RelativeLayout Example<br />
308<br />
jeudi 26 janvier 12<br />
Click on an entry to show which part of screen it corresponds to,<br />
and to get <strong>de</strong>tails about the XML attributes.<br />
Details: http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/<strong>de</strong>veloping/<strong>de</strong>bugging/<strong>de</strong>bugging-ui.html
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Other Layouts<br />
• AbsoluteLayout<br />
–From ol<strong>de</strong>r versions; now <strong>de</strong>precated; use RelativeLayout<br />
• FrameLayout<br />
–For formatting a single item. Usually used explicitly with<br />
TabHost. Used internally by other layouts.<br />
• TabHost<br />
–Combines tabs with switching Activities. Covered in later<br />
lecture on Intents and Activity switching.<br />
• ListView and GridView<br />
310<br />
jeudi 26 janvier 12<br />
–Not generalized layouts, but have somewhat similar role.<br />
Covered in later lecture.
More Reading<br />
• Tutorial: Declaring Layout<br />
–http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/topics/ui/<br />
<strong>de</strong>claring-layout.html<br />
• Tutorial: Hello Views<br />
–http://<strong>de</strong>veloper.android.com/resources/tutorials/views/<br />
• Has sub-sections on LinearLayout, RelativeLayout, and<br />
TableLayout<br />
• Chapter: Working with Containers<br />
–From The Busy Co<strong>de</strong>r’s Gui<strong>de</strong> to Android Development by<br />
Mark Murphy.<br />
• http://commonsware.com/Android/<br />
• Chapter: User Interface Layout<br />
311<br />
jeudi 26 janvier 12<br />
–From The Android Developer’s Cookbook by Steele & To
Summary<br />
• LinearLayout<br />
– I<strong>de</strong>as<br />
• One row or one column.<br />
• Nesting is key window-layout strategy<br />
– Key XML attributes<br />
• android:orientation, android:layout_weight<br />
• RelativeLayout<br />
– I<strong>de</strong>a<br />
• Position later component relative to earlier one<br />
– Key XML attributes<br />
• android:layout_alignBottom (and similar),<br />
android:layout_toLeftOf (and similar)<br />
• TableLayout<br />
– I<strong>de</strong>a<br />
• Put components in a grid<br />
– Key XML attributes for entries insi<strong>de</strong> TableRow<br />
• android:layout_column, android:layout_span<br />
312<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Android Coding Style Conventions<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Why follow conventions?<br />
• Valuable conventions<br />
–Ones that are wi<strong>de</strong>ly consi<strong>de</strong>red good practice for any Java<br />
project (based on general Java industry consensus)<br />
• Tolerable conventions<br />
–Ones that do no harm, but are of questionable value<br />
(in Marty’s highly subjective opinion)<br />
• Dubious conventions<br />
314<br />
jeudi 26 janvier 12<br />
–Ones that we would have been better off without<br />
(in Marty’s highly subjective opinion)
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Official Android Co<strong>de</strong><br />
Conventions<br />
• Required for<br />
– Co<strong>de</strong> contributed to Android project<br />
• Used in<br />
– All official tutorials and (supposedly) all source co<strong>de</strong><br />
• Suggested for<br />
– Co<strong>de</strong> submitted to the app store<br />
– Any Android project<br />
• Details<br />
– http://source.android.com/source/co<strong>de</strong>-style.html<br />
• Eclipse preferences file<br />
– Downloadable from coreservlets.com from this section of the<br />
Android Tutorial.<br />
• Sets spacing, brace style, and use of @Overri<strong>de</strong><br />
316<br />
jeudi 26 janvier 12
Pros and Cons of Following<br />
Conventions<br />
• Pros<br />
– Consistent with official tutorials and Android source<br />
– More familiar to Android <strong>de</strong>velopers who join your team<br />
• Cons<br />
– Inconsistent with Java co<strong>de</strong> you wrote before<br />
– Less familiar to other Java <strong>de</strong>velopers<br />
– Simply bothers you.<br />
• Java <strong>de</strong>velopers often have strong personal preferences<br />
• My recommendations<br />
– Most conventions are best practices anyhow<br />
• Definitely follow those<br />
– Most others are neither worse nor better than alternatives<br />
• Probably follow those<br />
– A few are (arguably) bad or at least wrong in some situations<br />
• Ignore those if the situation warrants it<br />
317<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Conventions that are Good<br />
Standard Practice<br />
(For any Java project)<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
In<strong>de</strong>ntation: blocks that are nested<br />
more should be in<strong>de</strong>nted more<br />
• Yes<br />
blah;<br />
blah;<br />
for(...) {<br />
}<br />
319<br />
jeudi 26 janvier 12<br />
blah;<br />
blah;<br />
for(...) {<br />
}<br />
blah;<br />
blah;<br />
• No<br />
blah;<br />
blah;<br />
for(...) {<br />
blah;<br />
blah;<br />
for(...) {<br />
blah;<br />
blah;<br />
}<br />
}
In<strong>de</strong>ntation: blocks that are nested the same<br />
should be in<strong>de</strong>nted the same<br />
• Yes<br />
blah;<br />
blah;<br />
for(...) {<br />
}<br />
320<br />
jeudi 26 janvier 12<br />
blah;<br />
blah;<br />
for(...) {<br />
}<br />
blah;<br />
blah;<br />
• No<br />
blah;<br />
blah;<br />
for(...) {<br />
}<br />
}<br />
blah;<br />
blah;<br />
for(...) {<br />
blah;<br />
blah;
Break Things into Small Pieces<br />
• Write short methods<br />
–No official limit, but try to keep methods short and focused.<br />
Think often about how to refactor your co<strong>de</strong> to break it into<br />
smaller and more reusable pieces.<br />
• This is good advice in any language.<br />
• This also shows why overly strict rules on the length of<br />
comments can be counter productive by encouraging <strong>de</strong>velopers<br />
to write long methods to avoid writing docs.<br />
• Keep lines short<br />
321<br />
jeudi 26 janvier 12<br />
–They have a strict rule of 100 characters except for imports or<br />
comments that contain URLs or commands that cannot be<br />
broken up.<br />
• Not sure 100 is the magic number, but short lines are good<br />
practice anyhow.
Follow Normal Capitalization<br />
Rules<br />
• Classes start with uppercase letter<br />
public class SomeClass { … }<br />
• Constants use all caps<br />
public static final double GOLDEN_RATIO =<br />
(1 + Math.sqrt(5.0))/2;<br />
• Everything else starts with lowercase letter<br />
–Instance variables, local variables, parameters to methods,<br />
package names<br />
• Extra rule<br />
322<br />
jeudi 26 janvier 12<br />
–Use words for acronyms, not all uppercase<br />
• getUrl, not getURL<br />
– This is good advice in Web apps also
Use JavaDoc<br />
• Use JavaDoc from the beginning<br />
–Don’t wait until the co<strong>de</strong> is finished. Short comments are fine,<br />
but use some. Explain purpose and non-obvious behavior.<br />
Don’t explain standard Java constructs.<br />
• Document every class<br />
/** Represents a collection of Blahs. Used to … **/<br />
public class Foo { … }<br />
• Document anything public<br />
–Methods<br />
–Constructors<br />
–Instance variables (but very rare to have public ones)<br />
• Review Oracle JavaDoc gui<strong>de</strong>lines<br />
• http://www.oracle.com/technetwork/java/javase/documentation/in<strong>de</strong>x-137868.html<br />
323<br />
jeudi 26 janvier 12
Use @Overri<strong>de</strong><br />
• Use @Overri<strong>de</strong> when you overri<strong>de</strong> methods<br />
from parent class<br />
–Won’t be caught until run time<br />
public void oncreate(Bundle savedInstanceState) {<br />
…<br />
}<br />
–Will be caught at compile time<br />
@Overri<strong>de</strong><br />
public void oncreate(Bundle savedInstanceState) {<br />
…<br />
}<br />
• Gui<strong>de</strong>lines are silent regarding interfaces<br />
324<br />
jeudi 26 janvier 12<br />
–But, in Java 6 or later, I prefer to also use @Overri<strong>de</strong> when<br />
implementing methods from interface
Use Other Standard Annotations<br />
when Warranted (but Rarely)<br />
• @Deprecated<br />
–If you use a <strong>de</strong>precated method, add this annotation to your<br />
method. Also add @<strong>de</strong>precated JavaDoc tag explaining why it<br />
was necessary to use <strong>de</strong>pracated co<strong>de</strong>.<br />
• Of course, try hard to avoid use of <strong>de</strong>precated methods<br />
• @SuppressWarnings<br />
325<br />
jeudi 26 janvier 12<br />
–Generic collections are prohibited from doing extra work at<br />
run time, so casting to generic type can cause warning that<br />
Java can’t verify the types. Sometimes unavoidable<br />
• @SuppressWarnings("unchecked")<br />
• Other similar situations when making generic types<br />
–Android gui<strong>de</strong>lines require a TODO comment in these cases,<br />
saying why you cannot avoid the situation
Limit the Scope of Variables<br />
• Use narrowest scope possible<br />
– Variables should be <strong>de</strong>clared in the innermost block that encloses<br />
all uses of the variable.<br />
• E.g., if variable is only used insi<strong>de</strong> if statement, <strong>de</strong>clare it insi<strong>de</strong> if<br />
statement.<br />
– Yes<br />
if (…) {<br />
double d = someCalculation(…);<br />
doSomethingWith(d);<br />
} else {<br />
// No use of d<br />
}<br />
– No<br />
double d = 0;<br />
if (…) { … } else { … }<br />
326<br />
jeudi 26 janvier 12
Initialize Local Variables when<br />
Declared<br />
• Initialize (almost) all local variables<br />
327<br />
jeudi 26 janvier 12<br />
–Yes<br />
String s = "Hello";<br />
–No<br />
String s;<br />
…<br />
s = "Hello";<br />
–Exception: try/catch blocks<br />
int n;<br />
try {<br />
n = Integer.parseInt(someString);<br />
} catch(NumberFormatException nfe) {<br />
n = 10;<br />
}
Put Braces on Conditionals<br />
• Always use braces for if statements<br />
–Even if there is only one thing to do<br />
• Yes<br />
if (…) {<br />
• No<br />
}<br />
doSomething();<br />
if (…)<br />
doSomething();<br />
• Gui<strong>de</strong>lines give small exception<br />
328<br />
jeudi 26 janvier 12<br />
–If there is only one thing to do and it is all on one line<br />
• Tolerated (grudgingly?)<br />
if (…) doSomething();
Use TODO Comments for<br />
Temporary Co<strong>de</strong><br />
• Use “// TODO: … ” for co<strong>de</strong> that needs to be<br />
changed later<br />
–Situations<br />
• Temporary fix<br />
• OK but not great<br />
• Works for small sizes, but bad performance in future when data<br />
sets get bigger.<br />
–Examples:<br />
// TODO: Switch to a Map when you have more entries<br />
// TODO: Remove after UrlTable2 has been checked in<br />
• Eclipse note<br />
329<br />
jeudi 26 janvier 12<br />
–Eclipse puts TODO in bold and puts check mark in left<br />
margin of co<strong>de</strong>
Avoid Finalizers<br />
• Do not use finalize()<br />
–I<strong>de</strong>a<br />
• finalize() gets called when an object is garbage collected, so you<br />
can do cleanup work then (such as closing socket connections)<br />
–Problem<br />
• No guarantee when (or even if) finalizer will be called<br />
–Gui<strong>de</strong>lines<br />
• Don’t use them.<br />
• Good news<br />
330<br />
jeudi 26 janvier 12<br />
–Finalizers have long ago fallen out of favor, and many Java<br />
<strong>de</strong>velopers don’t even know what they are.
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Conventions that<br />
Don’t Hurt<br />
(No harm in following them, but<br />
their value is questionable)<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Put Open Braces with Preceding<br />
Co<strong>de</strong><br />
• Put { with previous line, not on its own line<br />
332<br />
jeudi 26 janvier 12<br />
–Yes<br />
public void foo() {<br />
if (...) {<br />
doSomething();<br />
}<br />
}<br />
–No public void foo()<br />
{<br />
}<br />
if (...)<br />
{<br />
doSomething();<br />
}
In<strong>de</strong>nt 4 Spaces for Blocks<br />
• In<strong>de</strong>nt 4 spaces when starting a block<br />
333<br />
jeudi 26 janvier 12<br />
–Yes<br />
public void foo() {<br />
if (...) {<br />
doSomething();<br />
}<br />
}<br />
–No<br />
public void foo() {<br />
if (...) {<br />
doSomething();<br />
}<br />
}
In<strong>de</strong>nt 8 Spaces for Lines<br />
• In<strong>de</strong>nt 8 spaces when splitting a line<br />
334<br />
jeudi 26 janvier 12<br />
–Yes<br />
String s =<br />
somethingVeryLong(…);<br />
–No<br />
String s =<br />
somethingVeryLong(…);
Fully Qualify Imports<br />
• List each class name; don’t use *<br />
–Yes<br />
• import android.widget.Button;<br />
• import android.widget.CheckBox;<br />
• import android.widget.EditText;<br />
–No<br />
• import android.widget.*;<br />
• Exception<br />
335<br />
jeudi 26 janvier 12<br />
–Can use * for java or javax packages<br />
• Permitted<br />
– import java.util.*;
Or<strong>de</strong>r Import Statements<br />
• First<br />
– Android packages<br />
• import android.foo.Bar;<br />
• Second<br />
– Third party packages<br />
• import com.coreservlets.utils.RandomUtils;<br />
• Third<br />
– Standard java or javax packages<br />
• import java.util.*;<br />
• Within each group<br />
– Alphabetical (uppercase Z before lowercase a)<br />
• Separating groups<br />
– Blank line between each major grouping<br />
336<br />
jeudi 26 janvier 12
Start JavaDoc Comments with 3 rd<br />
Person Verb<br />
• Examples<br />
–Yes<br />
• Represents a …<br />
• Responds to mouse clicks with …<br />
• Deletes …<br />
–No<br />
• This class …<br />
• This method …<br />
• Android’s own docs are inconsistent<br />
337<br />
jeudi 26 janvier 12<br />
–Many (most?) classes start with “This class” or similar.<br />
• E.g., View, Activity, LinearLayout
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Questionable Conventions<br />
(You would have been<br />
better off without them)<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Start Instance Variables with<br />
“m” (normal) or “s” (static)<br />
• Use “m” for non-public, non static fields<br />
– “m” for “member variable” or “data member”<br />
• Yes<br />
– private String mFirstName;<br />
– private boolean mIsMarried;<br />
• No<br />
– private String firstName;<br />
– private boolean isMarried;<br />
• Use “s” for static (non-final) fields<br />
• Yes<br />
– private static double sBiggestRadius;<br />
• No<br />
– private static double biggestRadius;<br />
• Marty’s opinion<br />
– Results in less readable names with no real benefit<br />
339<br />
jeudi 26 janvier 12
Impact of Naming Convention<br />
on Constructors<br />
Standard Style<br />
public class Person {<br />
public String firstName, lastName;<br />
}<br />
340<br />
public Person(String firstName,<br />
String lastName) {<br />
this.firstName = firstName;<br />
this.lastName = lastName;<br />
}<br />
…<br />
jeudi 26 janvier 12<br />
Android Style<br />
public class Person {<br />
public String mFirstName, mLastName;<br />
}<br />
public Person(String firstName,<br />
String lastName) {<br />
mFirstName = firstName;<br />
mLastName = lastName;<br />
}<br />
…
Never Ignore Exceptions<br />
• Avoid empty catch blocks<br />
341<br />
jeudi 26 janvier 12<br />
–Yes<br />
try {<br />
…<br />
} catch(SomeException se) {<br />
doSomethingReal();<br />
}<br />
–No<br />
try {<br />
…<br />
} catch(SomeException se) { }<br />
–Marty’s opinion<br />
• Usually, but not always, a good rule
Why Ignoring Exceptions Rule is<br />
Too Strict<br />
• Can make shorter co<strong>de</strong> with same safety<br />
342<br />
jeudi 26 janvier 12<br />
–Android style<br />
int n;<br />
try {<br />
n = Integer.parseInt(…);<br />
} catch(NumberFormatException nfe) {<br />
n = 10;<br />
}<br />
–Shorter style if you could ignore exceptions<br />
int n = 10;<br />
try {<br />
n = Integer.parseInt(…);<br />
} catch(NumberFormatException nfe) { }
Why Ignoring Exceptions Rule is<br />
Too Strict (Continued)<br />
• Sometimes there is nothing to be done<br />
try {<br />
Thread.sleep(…);<br />
} catch(InterruptedException ie) {<br />
// What could you do here?<br />
}<br />
doSomethingAfterThePause();<br />
343<br />
jeudi 26 janvier 12
Don’t Catch Generic Exception<br />
• List each Exception type<br />
–Yes<br />
try {<br />
…<br />
} catch(ExceptionType1 et1) {<br />
…<br />
} catch(ExceptionType2 et2) {<br />
…<br />
}<br />
344<br />
jeudi 26 janvier 12<br />
–No try {<br />
…<br />
} catch(Exception e) {<br />
…<br />
}
Why Generic Exception Rule is<br />
(Arguably) Too Strict<br />
• Listing each type is almost always best<br />
–So exceptions you didn’t expect don’t get caught there<br />
–So real failure-handling is not obscured<br />
• Sometimes combining is concise and safe<br />
345<br />
jeudi 26 janvier 12<br />
–E.g., if someString could be null, you could have either<br />
NumberFormatException or NullPointerException. But, in<br />
both cases, you just want to use original value for n.<br />
int n = 10;<br />
try {<br />
n = Integer.parseInt(someString);<br />
} catch(Exception e) { }
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary<br />
• Strictly follow conventions that reflect wi<strong>de</strong>ly<br />
accepted best practices<br />
– Also, familiarize yourself with best practices.<br />
• All <strong>de</strong>velopers who have worked with Java more than two years full<br />
time should read Josh Bloch’s Effective Java (2 nd Edition).<br />
– Even experts will learn something new and valuable<br />
• For other conventions, if you don’t strongly object,<br />
follow the conventions anyhow<br />
– Even if you don’t see any real value<br />
• If convention really bothers you, ignore it<br />
– Assuming it is not in category of generally accepted best<br />
practices. Personal taste plays role in many of them.<br />
347<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Intents, Intent Filters,<br />
and Invoking Activities:<br />
Part I: Using Class Name<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Part I<br />
–Invoking Activities by class name<br />
–Defining dimensions in res/values<br />
–Sending data via the “extras” Bundle<br />
• Part II<br />
–Invoking Activities with a URI<br />
–Sending data via parameters in the URI<br />
• Part III<br />
349<br />
jeudi 26 janvier 12<br />
–Invoking Activities with tabbed windows<br />
–Defining two-image icons in res/drawable
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
I<strong>de</strong>a<br />
• Android philosophy<br />
–Activities are small, single-screen units<br />
• Consequence<br />
–You need easy way to switch from one Activity to another<br />
• Approach: use Intent<br />
351<br />
jeudi 26 janvier 12<br />
–An abstract <strong>de</strong>scription of an operation to be performed<br />
–Intent can refer to class name of Activity or a URI<br />
–If a URI, then Activity registers as handler for the scheme,<br />
host name, or MIME type of the URI<br />
–In all cases, new Activity must have entry in<br />
AndroidManifest.xml in or<strong>de</strong>r to be invoked
Summary of Options<br />
• Invoke Activity by class name (Part I)<br />
–Exactly one Activity can match<br />
–New Activity must be in same project as original<br />
–Can send data via an “extras” Bundle<br />
• Invoke Activity by URI (Part II)<br />
–More than one Activity could match<br />
–New Activity need not be in the same project as original<br />
–Can send data via URI parameters or “extras” Bundle<br />
• Switch Activities via tabs (Part III)<br />
352<br />
jeudi 26 janvier 12<br />
–Can use class name or URI to specify Activity<br />
–New Activity must be in same project as original<br />
–Can send data via URI parameters or “extras” Bundle
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example Target Activity:<br />
Loan Payment Calculator<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Example Target Activity:<br />
Loan Calculator<br />
• Inputs<br />
–Loan amount<br />
–Interest rate (as a percent)<br />
–Loan period in months<br />
• Outputs<br />
–Monthly payment<br />
–Total payments over life of loan<br />
• Both are in same units<br />
(e.g., dollars) as the loan amount<br />
• Defaults<br />
354<br />
jeudi 26 janvier 12<br />
–Unless values are passed in from other Activity, uses <strong>de</strong>fault<br />
values for all inputs
Summary of Layout<br />
355<br />
jeudi 26 janvier 12<br />
Entries in first column<br />
are right-aligned.<br />
Entries in second column are<br />
left-aligned. They are also given<br />
ids so that the Java co<strong>de</strong> can<br />
insert the text.<br />
This is a View with<br />
android:column_span="2" and<br />
a fixed height.<br />
TableLayout
XML: Layout File: First Row<br />
(res/layout/loan_payment.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
356<br />
jeudi 26 janvier 12<br />
Second and third rows are very similar. Bottom two rows are almost the same except for a different textColor for the second column.
XML: Layout File: Divi<strong>de</strong>r<br />
(res/layout/loan_payment.xml)<br />
357<br />
jeudi 26 janvier 12<br />
<br />
<br />
XML: Strings File<br />
(res/values/strings.xml)<br />
<br />
<br />
Intent Filters and Activity Switching<br />
<br />
Loan Calculator: Monthly Payments<br />
<br />
Tabbed Windows<br />
Loan amount:  <br />
Interest rate:  <br />
Months:  <br />
Monthly payment:  <br />
Total payments:  <br />
<br />
358<br />
jeudi 26 janvier 12<br />
The same prompts will also be used in a later input form.<br />
Note that   represents a non-breaking space. Regular spaces are not preserved at the beginning and end of strings in Android<br />
resource files. Note also that is not legal here, since that is a character entity specific to HTML, not general in XML.
XML: Colors File<br />
(res/values/colors.xml)<br />
<br />
<br />
<br />
#d3d3d3<br />
#ffffff<br />
#ff0000<br />
<br />
359<br />
jeudi 26 janvier 12
XML: Dimensions File<br />
(res/values/dimensions.xml)<br />
<br />
<br />
20dp<br />
<br />
360<br />
jeudi 26 janvier 12<br />
If you haven't seen a dimensions file before, note that the file name is arbitrary, as with all of the resource files in res/values. However, dimensions.xml is<br />
a common convention. Since they come with units (dp, sp, px, in, mm), you cannot store dimensions as regular strings. Dimensions are supplied via<br />
"@dimen/some_name" to attributes that expect font sizes, margin sizes, widths, heights, etc. In this case, "@dimen/font_size" was supplied for the<br />
android:textSize attribute of each of the TextViews.
Java (LoanCalculatorActivity.java)<br />
public class LoanCalculatorActivity extends Activity {<br />
private double mLoanAmount=100000,<br />
mAnnualInterestRateInPercent=5.0;<br />
private long mLoanPeriodInMonths=360; // 30 years<br />
private String mCurrencySymbol = "$";<br />
361<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.loan_payments);<br />
setInputsFromExtras();<br />
setInputsFromUri();<br />
calculateAndSetOutputValues();<br />
}<br />
We will explain setInputsFromExtras in an upcoming subsection. We will explain setInputsfromUri in Part II of the<br />
Intents series. For now, these methods make no changes to the instance variables, and the <strong>de</strong>fault values of the<br />
instance variables (shown at the top) will be used by calculateAndSetOutputValues.
Java, Continued<br />
(LoanCalculatorActivity.java)<br />
private void calculateAndSetOutputValues() {<br />
PaymentInfo paymentInfo =<br />
new PaymentInfo(mLoanAmount, mAnnualInterestRateInPercent,<br />
mLoanPeriodInMonths, mCurrencySymbol);<br />
TextView loanAmountDisplay = (TextView)findViewById(R.id.loan_amount);<br />
loanAmountDisplay.setText(paymentInfo.getFormattedLoanAmount());<br />
TextView interestRateDisplay =<br />
(TextView)findViewById(R.id.interest_rate);<br />
interestRateDisplay.setText<br />
(paymentInfo.getFormattedAnnualInterestRateInPercent());<br />
TextView loanPeriodDisplay = (TextView)findViewById(R.id.loan_period);<br />
loanPeriodDisplay.setText(paymentInfo.getFormattedLoanPeriodInMonths());<br />
TextView monthlyPaymentDisplay =<br />
(TextView)findViewById(R.id.monthly_payment);<br />
monthlyPaymentDisplay.setText(paymentInfo.getFormattedMonthlyPayment());<br />
TextView totalPaymentsDisplay =<br />
(TextView)findViewById(R.id.total_payments);<br />
totalPaymentsDisplay.setText(paymentInfo.getFormattedTotalPayments());<br />
}<br />
362<br />
jeudi 26 janvier 12<br />
The math is done in the PaymentInfo class (next sli<strong>de</strong>s) at the top of the method,<br />
which in turn calls the LoanUtils class (following sli<strong>de</strong>s). The rest of the co<strong>de</strong> just<br />
assigns the output values to the TextViews that are in the second column of the table<br />
from the layout file (res/layouts/loan_payments.xml).
Java (PaymentInfo.java)<br />
public class PaymentInfo {<br />
private final double mLoanAmount, mAnnualInterestRateInPercent,<br />
mMonthlyPayment, mTotalPayments;<br />
private final long mLoanPeriodInMonths;<br />
private final String mCurrencySymbol;<br />
}<br />
363<br />
jeudi 26 janvier 12<br />
public PaymentInfo(double loanAmount, double annualInterestRateInPercent,<br />
long loanPeriodInMonths, String currencySymbol) {<br />
mLoanAmount = loanAmount;<br />
mAnnualInterestRateInPercent = annualInterestRateInPercent;<br />
mLoanPeriodInMonths = loanPeriodInMonths;<br />
mCurrencySymbol = currencySymbol;<br />
mMonthlyPayment = LoanUtils.monthlyPayment(loanAmount,<br />
annualInterestRateInPercent,<br />
loanPeriodInMonths);<br />
mTotalPayments = mMonthlyPayment * mLoanPeriodInMonths;<br />
}<br />
...<br />
The remaining methods are just getter methods and variations of the getter methods<br />
that return the values as formatted strings (e.g., with commas and with exactly two<br />
values after the <strong>de</strong>cimal point).
Java (LoanUtils.java)<br />
public class LoanUtils {<br />
public static double monthlyPayment(double loanAmount,<br />
double annualInterestRateInPercent,<br />
long loanPeriodInMonths) {<br />
if (annualInterestRateInPercent
Example: Results<br />
365<br />
jeudi 26 janvier 12<br />
For now, these values are fixed to the initial values set<br />
for the instance variables of the<br />
LoanCalculatorActivity. However, the upcoming<br />
sections will show how to pass values from another<br />
Activity to this one.<br />
Computed by LoanUtils. Formatted by<br />
PaymentInfo.
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Invoking Activities by<br />
Class Name<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary<br />
• I<strong>de</strong>a<br />
– Specify class name of new Activity<br />
• New Activity must be in same project as original Activity<br />
• Syntax<br />
– Java (original Activity)<br />
367<br />
jeudi 26 janvier 12<br />
Intent activityIntent = new Intent(this, NewActivity.class);<br />
startActivity(activityIntent);<br />
– XML (AndroidManifest.xml)<br />
<br />
<br />
<br />
<br />
<br />
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example:<br />
Invoking Loan Calculator<br />
with Default Values<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Example: Overview<br />
• Initial Activity<br />
–Has Button that, when pressed,<br />
invokes the loan calculator activity<br />
• No data is sent to the loan calculator,<br />
so it will use <strong>de</strong>fault values for the<br />
loan amount, interest rate, etc.<br />
• Approach<br />
369<br />
jeudi 26 janvier 12<br />
–Create Intent referring to LoanCalculatorActivity.class<br />
• Thus, the two Activities must be in same project<br />
–Call startActivity<br />
–Put entry for LoanCalculatorActivity in AndroidManifest.xml<br />
• So that the initial Activity has permission to invoke the loan<br />
calculator
XML: Layout File<br />
(res/layout/main.xml)<br />
<br />
<br />
<br />
...<br />
<br />
370<br />
jeudi 26 janvier 12<br />
Other buttons shown later
XML: Manifest File Template<br />
(AndroidManifest.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
371<br />
jeudi 26 janvier 12<br />
Other Activities will be<br />
<strong>de</strong>clared here.<br />
See next sli<strong>de</strong> for<br />
LoanCalculatorActivity.<br />
Means that this is the<br />
Action that runs when<br />
you run the project.<br />
This part is generated automatically<br />
when you build a new Android<br />
project in Eclipse.<br />
Means that this app<br />
gets an icon on the<br />
screen of your Android<br />
<strong>de</strong>vice.
XML: Manifest File<br />
Action Declaration<br />
<br />
<br />
<br />
<br />
... <br />
<br />
<br />
<br />
<br />
... <br />
<br />
<br />
...<br />
<br />
<br />
372<br />
jeudi 26 janvier 12<br />
The "data" tag of the land the "activity" tag for the tabbed<br />
windows Activity are both shown later.<br />
Use the fully-qualified name if the new Activity is in a<br />
different package than the main one (i.e., the one<br />
listed at the top in the "manifest" start tag).<br />
Means that this Action<br />
displays data to the user,<br />
but is not launched as the<br />
initial Activity of the project.<br />
Means that this Action can<br />
be the <strong>de</strong>fault for certain<br />
types of data (shown later).<br />
You virtually always set action.VIEW and category.DEFAULT for<br />
Activities that will be invoked by other Activities.
XML: Strings File<br />
(res/values/strings.xml)<br />
<br />
<br />
<br />
Intent Filters and Activity Switching<br />
<br />
...<br />
<br />
373<br />
jeudi 26 janvier 12<br />
Other strings shown earlier, and apply to the LoanCalculatorActivity, not to the initial Activity with the buttons that launch the loan calculator.
Java (IntentFilter1Activity.java)<br />
public class IntentFilter1Activity extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
}<br />
}<br />
374<br />
jeudi 26 janvier 12<br />
public void showLoanPayments1(View clickedButton) {<br />
Intent activityIntent =<br />
new Intent(this, LoanCalculatorActivity.class);<br />
startActivity(activityIntent);<br />
}<br />
...<br />
Event handler methods for other buttons shown later
Example: Results<br />
375<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Sending Data via the<br />
“Extras” Bundle<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary<br />
• I<strong>de</strong>a<br />
– Attach a Bundle (like a Map – see next sli<strong>de</strong>s) to the Intent. The<br />
Bundle will contain data to be used by the new Activity.<br />
• Syntax<br />
– Java (original Activity)<br />
Intent activityIntent = new Intent(this, NewActivity.class);<br />
Bundle newActivityInfo = new Bundle();<br />
newActivityInfo.putBlah(…); // putDouble, putString, etc.<br />
activityIntent.putExtras(newActivityInfo);<br />
startActivity(activityIntent);<br />
– Java (new Activity)<br />
Intent intent = getIntent();<br />
Bundle info = intent.getExtras();<br />
if (info != null) { /* Retrieve vals with info.getBlah(...) */ }<br />
377<br />
jeudi 26 janvier 12
The Bundle Class: Details<br />
• Putting data in a Bundle<br />
– putBoolean, putBooleanArray, putDouble, putDoubleArray,<br />
putString, putStringArray, etc.<br />
• These all take keys and values as arguments.<br />
The keys must be Strings. The values must be of the standard types<br />
(int, double, etc.) or array of them.<br />
– You can also make a custom class that implements Serializable or Parceleable, then<br />
store instance of that class with putSerializable or putParceleable<br />
• Methods return void, so you cannot chain as with the putExtra method<br />
of Intent.<br />
• Retrieving data from a Bundle<br />
– getBoolean, getBooleanArray, getDouble, getDoubleArray,<br />
getString, getStringArray, etc.<br />
• These take keys (Strings) as arguments.<br />
No typecast required on retrieval.<br />
378<br />
jeudi 26 janvier 12
Option 1: Attaching Entire Bundle<br />
to Intent<br />
• I<strong>de</strong>a<br />
–Make a Bundle, add it all at once to Intent.<br />
• Instantiate a Bundle, then use the Bundle’s putBlah method (one<br />
such method for each standard type). Then, attach Bundle to<br />
Intent with Intent’s putExtras method.<br />
• Syntax<br />
Bundle newActivityInfo = new Bundle();<br />
newActivityInfo.putDouble("key1", someDouble);<br />
newActivityInfo.putString("key2", someString);<br />
…<br />
yourIntent.putExtras(newActivityInfo);<br />
379<br />
jeudi 26 janvier 12<br />
– Note that it is putExtras, not putExtra
Option 2: Adding One Piece of<br />
Data at a Time to Intent<br />
• I<strong>de</strong>a<br />
–Add individual pieces of data to the Intent. No need to<br />
explicitly create and attach a Bundle.<br />
• You use the overloa<strong>de</strong>d “putExtra” method. The first argument is<br />
the key (String), and the second argument is the value, which<br />
can be of any standard type. However, the co<strong>de</strong> that retrieves the<br />
value later needs to know type.<br />
• Syntax<br />
yourIntent.putExtra("key1", someDouble);<br />
yourIntent.putExtra("key2", someString);<br />
…<br />
– Unlike putBlah for Bundle, these putExtra methods return the Intent, so you<br />
can do jQuery-like chaining:<br />
380<br />
jeudi 26 janvier 12<br />
» yourIntent.putExtra(…).putExtra(…) … .putExtra(…);
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example:<br />
Invoking Loan Calculator<br />
with Custom Values<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Example: Overview<br />
• Initial Activity<br />
–Has Button that, when pressed,<br />
invokes the loan calculator activity<br />
• Creates randomized data and<br />
sends it to the loan calculator, which<br />
retrieves the values and uses them<br />
for its calculations.<br />
• Approach<br />
382<br />
jeudi 26 janvier 12<br />
–Create Intent referring to LoanCalculatorActivity.class<br />
–Create Bundle with 3 values<br />
• Loan amount, interest rate, loan period<br />
–Attach Bundle to Intent with putExtras<br />
–Call startActivity<br />
–Put entry for LoanCalculatorActivity in manifest
XML: Layout File<br />
(res/layout/main.xml)<br />
<br />
<br />
...<br />
<br />
...<br />
<br />
383<br />
jeudi 26 janvier 12<br />
First button shown earlier
XML: Manifest File<br />
Action Declaration<br />
<br />
<br />
<br />
<br />
... <br />
<br />
<br />
<br />
<br />
... <br />
<br />
<br />
...<br />
<br />
<br />
384<br />
jeudi 26 janvier 12<br />
No changes from previous example.
Java (IntentFilter1Activity.java)<br />
public class IntentFilter1Activity extends Activity {<br />
...<br />
}<br />
385<br />
jeudi 26 janvier 12<br />
public void showLoanPayments2(View clickedButton) {<br />
Intent activityIntent =<br />
new Intent(this, LoanCalculatorActivity.class);<br />
activityIntent.putExtras<br />
(LoanBundler.makeRandomizedLoanInfoBundle());<br />
startActivity(activityIntent);<br />
}<br />
...<br />
Co<strong>de</strong> for onCreate and first button’s event handler shown earlier.
Java (LoanBundler.java)<br />
public class LoanBundler {<br />
public static Bundle makeLoanInfoBundle(double loanAmount,<br />
double annualInterestRateInPercent,<br />
long loanPeriodInMonths,<br />
String currencySymbol) {<br />
Bundle loanInfo = new Bundle();<br />
loanInfo.putDouble("loanAmount", loanAmount);<br />
loanInfo.putDouble("annualInterestRateInPercent",<br />
annualInterestRateInPercent);<br />
loanInfo.putLong("loanPeriodInMonths", loanPeriodInMonths);<br />
loanInfo.putString("currencySymbol", currencySymbol);<br />
return(loanInfo);<br />
}<br />
386<br />
jeudi 26 janvier 12
Java<br />
(LoanBundler.java, Continued)<br />
387<br />
jeudi 26 janvier 12<br />
public static Bundle makeRandomizedLoanInfoBundle() {<br />
Random randomizer = new Random();<br />
double loanAmount = 25000 * (1 + randomizer.nextInt(10));<br />
double interestRate = 0.25 * (1 + randomizer.nextInt(60));<br />
long loanPeriod = 12 * (1 + randomizer.nextInt(30));<br />
return(LoanBundler.makeLoanInfoBundle(loanAmount,<br />
interestRate, loanPeriod));<br />
}
Java (LoanCalculatorActivity.java)<br />
public class LoanCalculatorActivity extends Activity {<br />
private double mLoanAmount=100000,<br />
mAnnualInterestRateInPercent=5.0;<br />
private long mLoanPeriodInMonths=360; // 30 years<br />
private String mCurrencySymbol = "$";<br />
388<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.loan_payments);<br />
setInputsFromExtras();<br />
setInputsFromUri();<br />
calculateAndSetOutputValues();<br />
}
Java (LoanCalculatorActivity,<br />
Continued)<br />
389<br />
jeudi 26 janvier 12<br />
private void setInputsFromExtras() {<br />
Intent intent = getIntent();<br />
Bundle loanInfo = intent.getExtras();<br />
if (loanInfo != null) {<br />
double loanAmount = loanInfo.getDouble("loanAmount");<br />
double annualInterestRateInPercent =<br />
loanInfo.getDouble("annualInterestRateInPercent");<br />
long loanPeriodInMonths =<br />
loanInfo.getLong("loanPeriodInMonths");<br />
String currencySymbol =<br />
loanInfo.getString("currencySymbol");<br />
setInputs(loanAmount, annualInterestRateInPercent,<br />
loanPeriodInMonths, currencySymbol);<br />
}<br />
}
Java (LoanCalculatorActivity,<br />
Continued)<br />
390<br />
jeudi 26 janvier 12<br />
private void setInputs(double loanAmount,<br />
double annualInterestRateInPercent,<br />
long loanPeriodInMonths,<br />
String currencySymbol) {<br />
if (loanAmount > 0) {<br />
mLoanAmount = loanAmount;<br />
}<br />
if (annualInterestRateInPercent > 0) {<br />
mAnnualInterestRateInPercent =<br />
annualInterestRateInPercent;<br />
}<br />
if (loanPeriodInMonths > 0) {<br />
mLoanPeriodInMonths = loanPeriodInMonths;<br />
}<br />
if (currencySymbol != null) {<br />
mCurrencySymbol = currencySymbol;<br />
}<br />
}
Example: Results<br />
391<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
More Reading<br />
• Tutorial: Intents and Intent Filters<br />
–http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/topics/intents/<br />
intents-filters.html<br />
• JavaDoc: Intent<br />
–http://<strong>de</strong>veloper.android.com/reference/android/content/<br />
Intent.html<br />
• Chapters: Creating Intent Filters and<br />
Launching Activities and Sub-Activities<br />
–From The Busy Co<strong>de</strong>r’s Gui<strong>de</strong> to Android Development<br />
• http://commonsware.com/Android/<br />
• Chapter: Intents and Services<br />
393<br />
jeudi 26 janvier 12<br />
–From Android in Action by Ableson et al
Summary<br />
• Java (original Activity)<br />
Intent activityIntent = new Intent(this, NewActivity.class);<br />
Bundle newActivityInfo = new Bundle();<br />
newActivityInfo.putBlah(…); // putDouble, putString, etc.<br />
activityIntent.putExtras(newActivityInfo);<br />
startActivity(activityIntent);<br />
• Java (new Activity)<br />
Intent intent = getIntent();<br />
Bundle info = intent.getExtras();<br />
if (info != null) { /* Retrieve vals with info.getBlah(...) */ }<br />
• XML (AndroidManifest.xml)<br />
<br />
<br />
<br />
<br />
394<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Intents, Intent Filters,<br />
and Invoking Activities:<br />
Part II: Using URI<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Part I<br />
–Invoking Activities by class name<br />
–Defining dimensions in res/values<br />
–Sending data via the “extras” Bundle<br />
• Part II<br />
–Invoking Activities with a URI<br />
–Sending data via parameters in the URI<br />
• Part III<br />
396<br />
jeudi 26 janvier 12<br />
–Invoking Activities with tabbed windows<br />
–Defining two-image icons in res/drawable
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary of Options<br />
• Invoke Activity by class name (Part I)<br />
–Exactly one Activity can match<br />
–New Activity must be in same project as original<br />
–Can send data via an “extras” Bundle<br />
• Invoke Activity by URI (Part II)<br />
–More than one Activity could match<br />
–New Activity need not be in the same project as original<br />
–Can send data via URI parameters or “extras” Bundle<br />
• Switch Activities via tabs (Part III)<br />
398<br />
jeudi 26 janvier 12<br />
–Can use class name or URI to specify Activity<br />
–New Activity must be in same project as original<br />
–Can send data via URI parameters or “extras” Bundle
jeudi 26 janvier 12<br />
Invoking Activities<br />
with a URI<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary<br />
• I<strong>de</strong>a<br />
– Supply a URI that indirectly refers to new Activity. The new Activity registers<br />
as target for URIs of a certain form.<br />
• The originating Activity and the new Activity need not be in the same project<br />
• More than one Activity could match the URI.<br />
– If so, Android will ask you which one to use.<br />
• Syntax<br />
– Java (original Activity)<br />
400<br />
jeudi 26 janvier 12<br />
Uri uri = Uri.parse("foo://bar.example.com/baz");<br />
Intent intent = new Intent(Intent.ACTION_VIEW, uri);<br />
startActivity(activityIntent);<br />
– XML (AndroidManifest.xml)<br />
<br />
<br />
<br />
<br />
Registering to Handle URIs<br />
• Matching the URI itself<br />
–Register for a scheme and a host<br />
• Example URI<br />
– loan://coreservlets.com/calc<br />
• intent-filter entry<br />
– <br />
• Matching the data type<br />
–Register for a MIME type<br />
• Example URIs<br />
– content:// (referring to that MIME type)<br />
– file:// (referring to that MIME type)<br />
– anything:// (the Intent can call setType to specify MIME type)<br />
• intent-filter entry<br />
– <br />
– <br />
401<br />
jeudi 26 janvier 12
Pre<strong>de</strong>fined Action/URI<br />
Combinations<br />
402<br />
jeudi 26 janvier 12<br />
Action URI Meaning<br />
Intent.ACTION_CALL tel:phone_number Opens phone application and calls<br />
phone_number.<br />
Intent.ACTION_DIAL tel:phone_number Opens phone application and dials (but<br />
doesn’t call) phone_number.<br />
Intent.ACTION_DIAL voicemail: Opens phone application and dials (but<br />
doesn’t call) the voice mail number.<br />
Intent.ACTION_VIEW geo:lat,long Opens the maps application centered on<br />
(lat, long).<br />
Intent.ACTION_VIEW geo:0,0?q=address Opens the maps application centered on<br />
the specified address.<br />
Intent.ACTION_VIEW http://url<br />
https://url<br />
Intent.<br />
ACTION_WEB_SEARCH<br />
Opens the browser application to the<br />
specified address.<br />
plain_text Opens the browser application and uses<br />
Google search for given string.<br />
Table adapted from Section 4.1.5 of Android in Action by Ableson et al.
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example:<br />
Invoking Loan Calculator<br />
(Data in Extras Bundle)<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Example: Overview<br />
• Initial Activity<br />
–Has Button that, when pressed,<br />
invokes the loan calculator activity<br />
• Initial Activity uses URI to indirectly invoke loan calculator<br />
• Initial Activity is in different project than loan calculator<br />
• Data is sent via extras Bundle as in previous example<br />
• Approach<br />
404<br />
jeudi 26 janvier 12<br />
–Create Intent with Intent.ACTION_VIEW and URI of "loan://<br />
coreservlets.com/calc"<br />
–Create and attach Bundle as in previous example<br />
–Call startActivity<br />
–Put data entry for LoanCalculatorActivity in manifest<br />
–
XML: Layout File<br />
(res/layout/main.xml – 2 nd Proj.)<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
405<br />
jeudi 26 janvier 12<br />
Entries for input form and second<br />
button shown later.
XML: Manifest File<br />
Action Declaration (Loan Proj.)<br />
<br />
<br />
<br />
<br />
... <br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
406<br />
jeudi 26 janvier 12
Java (IntentFilter2Activity.java)<br />
public class IntentFilter2Activity extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
}<br />
}<br />
407<br />
jeudi 26 janvier 12<br />
public void showLoanPayments1(View clickedButton) {<br />
Uri uri = Uri.parse("loan://coreservlets.com/calc");<br />
Intent intent = new Intent(Intent.ACTION_VIEW, uri);<br />
intent.putExtras<br />
(LoanBundler.makeRandomizedLoanInfoBundle());<br />
startActivity(intent);<br />
}<br />
...<br />
Co<strong>de</strong> for second button (that embeds data in the URI) shown later.
Java Co<strong>de</strong> Shown Earlier<br />
• LoanBundler<br />
–Makes a Bundle that stores the loan amount, interest rate, and<br />
loan period<br />
• LoanCalculatorActivity<br />
408<br />
jeudi 26 janvier 12<br />
–Calls getIntent().getExtras() and reads the data out of the<br />
resultant Bundle. Uses that for the initial values for the loan<br />
amount, interest rate, and loan period<br />
–Passes the values to PaymentInfo, which in turn uses<br />
LoanUtils to calculate monthly payment and total payments<br />
–Puts all five values (loan amount, interest rate, loan period,<br />
monthly payment, total payments) into TextViews
Example: Results<br />
409<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Sending Data via<br />
Parameters in the URI<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary<br />
• I<strong>de</strong>a<br />
– Embed query parameters in the URI. These parameters will represent data<br />
to be used by the new Activity.<br />
• Syntax<br />
– Java (original Activity)<br />
411<br />
jeudi 26 janvier 12<br />
String address =<br />
"loan://coreservlets.com/calc?loanAmount=xxx&…";<br />
Uri uri = Uri.parse(address);<br />
Intent intent = new Intent(Intent.ACTION_VIEW, uri);<br />
startActivity(activityIntent);<br />
– Java (new Activity)<br />
Uri uri = getIntent().getData();<br />
String loanAmountString = uri.getQueryParameter("loanAmount");<br />
// Convert String to double<br />
...
Sending Data:<br />
Extras vs. URI Parameters<br />
• Extras Bundle<br />
–Pros<br />
• Can send data of different types.<br />
• No parsing required in Activity that receives the data.<br />
–Cons<br />
• More complex for originating Activity<br />
– Requires parsing in originating Activity if values come from EditText<br />
• URI parameters<br />
412<br />
jeudi 26 janvier 12<br />
–Pros<br />
• Simpler for originating Activity, especially if EditText used<br />
• More consistent with URI usage<br />
–Cons<br />
• Can send Strings only<br />
• Requires parsing in receiving Activity
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example:<br />
Invoking Loan Calculator<br />
(Data in URI Parameters)<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Example: Overview<br />
• Initial Activity<br />
–Has Button that, when pressed,<br />
invokes the loan calculator activity<br />
• Data is extracted from textfields (EditTexts) and embed<strong>de</strong>d in the<br />
URI that is used to invoke loan calculator<br />
• Approach<br />
414<br />
jeudi 26 janvier 12<br />
–Create Intent with Intent.ACTION_VIEW and URI of "loan://<br />
coreservlets.com/calc?data"<br />
• Data is<br />
"loanAmount=…&annualInterestRateInPercent=…&…"<br />
–Call startActivity<br />
–Put data entry for LoanCalculatorActivity in manifest<br />
–
XML: Layout File<br />
(res/layout/main.xml – 2 nd Proj.)<br />
<br />
<br />
...<br />
<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
415<br />
jeudi 26 janvier 12<br />
Entry for first button shown earlier. Entries for other textfields (EditTexts)<br />
similar to the one shown. Entry for button at the bottom just has<br />
android:onClick="showLoanPayments2".
XML: Strings File<br />
(res/values/strings.xml)<br />
<br />
<br />
Intent Filters and Activity Switching<br />
<br />
Loan Calculator: Monthly Payments<br />
<br />
Tabbed Windows<br />
Loan amount:  <br />
Interest rate:  <br />
Months:  <br />
Monthly payment:  <br />
Total payments:  <br />
<br />
416<br />
jeudi 26 janvier 12<br />
The same prompts are also used in the output display.<br />
Note that   represents a non-breaking space. Regular spaces are not preserved at the beginning and end of strings in Android<br />
resource files. Note also that is not legal here, since that is a character entity specific to HTML, not general in XML.
XML: Manifest File<br />
Action Declaration (Loan Proj.)<br />
<br />
<br />
<br />
<br />
... <br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
417<br />
jeudi 26 janvier 12<br />
Unchanged from previous example.
Java (IntentFilter2Activity.java)<br />
public class IntentFilter2Activity extends Activity {<br />
...<br />
418<br />
jeudi 26 janvier 12<br />
public void showLoanPayments2(View clickedButton) {<br />
String address = makeLoanAddressFromEditTextInputs();<br />
Uri uri = Uri.parse(address);<br />
Intent intent = new Intent(Intent.ACTION_VIEW, uri);<br />
startActivity(intent);<br />
}<br />
Co<strong>de</strong> for onCreate and first button shown earlier.
Java<br />
(IntentFilter2Activity, Continued)<br />
private String makeLoanAddressFromEditTextInputs() {<br />
EditText loanAmountInput = (EditText)findViewById(R.id.loan_amount);<br />
Editable loanAmount = loanAmountInput.getText();<br />
String loanAmountParam =<br />
String.format("loanAmount=%s", loanAmount);<br />
EditText interestRateInput = (EditText)findViewById(R.id.interest_rate);<br />
Editable interestRate = interestRateInput.getText();<br />
String interestRateParam =<br />
String.format("annualInterestRateInPercent=%s", interestRate);<br />
EditText loanPeriodInput = (EditText)findViewById(R.id.loan_period);<br />
Editable loanPeriod = loanPeriodInput.getText();<br />
String loanPeriodParam =<br />
String.format("loanPeriodInMonths=%s", loanPeriod);<br />
String baseAddress = "loan://coreservlets.com/calc";<br />
String address =<br />
String.format("%s?%s&%s&%s", baseAddress, loanAmountParam,<br />
interestRateParam, loanPeriodParam);<br />
return(address);<br />
}<br />
419<br />
jeudi 26 janvier 12
Java (LoanCalculatorActivity.java)<br />
public class LoanCalculatorActivity extends Activity {<br />
private double mLoanAmount=100000,<br />
mAnnualInterestRateInPercent=5.0;<br />
private long mLoanPeriodInMonths=360; // 30 years<br />
private String mCurrencySymbol = "$";<br />
420<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.loan_payments);<br />
setInputsFromExtras();<br />
setInputsFromUri();<br />
calculateAndSetOutputValues();<br />
}
Java (LoanCalculatorActivity,<br />
Continued)<br />
421<br />
jeudi 26 janvier 12<br />
private void setInputsFromUri() {<br />
Uri uri = getIntent().getData();<br />
if (uri != null) {<br />
double loanAmount = getDoubleParam(uri, "loanAmount");<br />
double annualInterestRateInPercent =<br />
getDoubleParam(uri, "annualInterestRateInPercent");<br />
long loanPeriodInMonths =<br />
getLongParam(uri, "loanPeriodInMonths");<br />
String currencySymbol =<br />
uri.getQueryParameter("currencySymbol");<br />
setInputs(loanAmount, annualInterestRateInPercent,<br />
loanPeriodInMonths, currencySymbol);<br />
}<br />
}<br />
getQueryParameter is the builtin method of Uri. getDoubleParam and getLongParam (next sli<strong>de</strong>s) are<br />
methods of LoanCalculatorActivity that call getQueryParameter and then parse the resultant String.
Java (LoanCalculatorActivity,<br />
Continued)<br />
422<br />
jeudi 26 janvier 12<br />
private void setInputsFromUri() {<br />
Uri uri = getIntent().getData();<br />
if (uri != null) {<br />
double loanAmount = getDoubleParam(uri, "loanAmount");<br />
double annualInterestRateInPercent =<br />
getDoubleParam(uri, "annualInterestRateInPercent");<br />
long loanPeriodInMonths =<br />
getLongParam(uri, "loanPeriodInMonths");<br />
String currencySymbol =<br />
uri.getQueryParameter("currencySymbol");<br />
setInputs(loanAmount, annualInterestRateInPercent,<br />
loanPeriodInMonths, currencySymbol);<br />
}<br />
}
Java (LoanCalculatorActivity,<br />
Continued)<br />
423<br />
jeudi 26 janvier 12<br />
private double getDoubleParam(Uri uri, String queryParamName) {<br />
String rawValue = uri.getQueryParameter(queryParamName);<br />
double value = 0.0;<br />
try {<br />
value = Double.parseDouble(rawValue);<br />
} catch(Exception e) { } // NumberFormatEx or NullPointerEx<br />
return(value);<br />
}<br />
private long getLongParam(Uri uri, String queryParamName) {<br />
String rawValue = uri.getQueryParameter(queryParamName);<br />
long value = 0;<br />
try {<br />
value = Long.parseLong(rawValue);<br />
} catch(Exception e) { } // NFE or NPE<br />
return(value);<br />
}
Example: Results<br />
424<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary<br />
• Java (original Activity)<br />
String address =<br />
"loan://coreservlets.com/calc?loanAmount=xxx&…";<br />
Uri uri = Uri.parse(address);<br />
Intent intent = new Intent(Intent.ACTION_VIEW, uri);<br />
startActivity(activityIntent);<br />
• Java (new Activity – can be different project)<br />
Uri uri = getIntent().getData();<br />
String loanAmountString = uri.getQueryParameter("loanAmount");<br />
// Convert String to double, handle bad data<br />
...<br />
• XML (AndroidManifest.xml)<br />
<br />
<br />
<br />
<br />
<br />
426<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Intents, Intent Filters,<br />
and Invoking Activities:<br />
Part III: Using Tabs<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Part I<br />
–Invoking Activities by class name<br />
–Defining dimensions in res/values<br />
–Sending data via the “extras” Bundle<br />
• Part II<br />
–Invoking Activities with a URI<br />
–Sending data via parameters in the URI<br />
• Part III<br />
428<br />
jeudi 26 janvier 12<br />
–Invoking Activities with tabbed windows<br />
–Defining two-image icons in res/drawable
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary of Options<br />
• Invoke Activity by class name (Part I)<br />
–Exactly one Activity can match<br />
–New Activity must be in same project as original<br />
–Can send data via an “extras” Bundle<br />
• Invoke Activity by URI (Part II)<br />
–More than one Activity could match<br />
–New Activity need not be in the same project as original<br />
–Can send data via URI parameters or “extras” Bundle<br />
• Switch Activities via tabs (Part III)<br />
430<br />
jeudi 26 janvier 12<br />
–Can use class name or URI to specify Activity<br />
–New Activity must be in same project as original<br />
–Can send data via URI parameters or “extras” Bundle
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Invoking Activities with<br />
Tabbed Windows<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary<br />
• I<strong>de</strong>a<br />
– Make tabbed windows. Each tab invokes a different Activity, or<br />
an Activity with different data.<br />
• Can use either specific-class approach or URI approach<br />
• Can send data either with an extras Bundle or in URI<br />
• Tab window Activity and new Activities must be in same project<br />
– Due to security reasons<br />
• Syntax<br />
– Java<br />
• Extends TabActivity. Uses TabHost and TabSpec<br />
432<br />
jeudi 26 janvier 12<br />
– Details on next sli<strong>de</strong><br />
– XML (AndroidManifest.xml)<br />
• Same as shown earlier
Using TabActivity: Outline<br />
public class SomeActivity extends TabActivity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
Resources resources = getResources();<br />
TabHost host = getTabHost();<br />
Intent intent1= ...;<br />
Drawable tabIcon =<br />
resources.getDrawable(R.drawable.icon_name);<br />
TabSpec tab1Spec =<br />
host.newTabSpec("Tab One")<br />
.setIndicator("Some Text", tabIcon)<br />
.setContent(intent1);<br />
host.addTab(tab1Spec);<br />
// Repeat for other tabs<br />
}<br />
}<br />
433<br />
jeudi 26 janvier 12<br />
Note that the setter methods for TabSpec return the TabSpec so that you can do chained assignments.<br />
Note also that there is no layout file when using this approach.
Defining Tab Icons<br />
• I<strong>de</strong>a<br />
–Although it is legal to call setIndicator(someString), the<br />
resultant tab looks bad because of blank space at top. So,<br />
more common to do setIndicator(someString, someIcon).<br />
• You can also do setIndicator(someView) for fancy tabs<br />
• Icon option 1<br />
–Use a single image for the icon<br />
• Same image used when the tab is or is not selected<br />
• Icon option 2<br />
434<br />
jeudi 26 janvier 12<br />
–Use 2 similar but differently colored images for the icon<br />
• One for when selected, one for when not
Option 1: A Single Image<br />
• Pros<br />
–Simpler<br />
–Text color and background color of the tab already change on<br />
selection, so not confusing if icon stays same.<br />
• Cons<br />
–Doesn’t look quite as good as with two images<br />
• Approach<br />
435<br />
jeudi 26 janvier 12<br />
–Put image file in res/drawable/some_icon.png<br />
–Refer to image with<br />
• Drawable tabIcon =<br />
resources.getDrawable(R.drawable.some_icon);<br />
–Put icon in tab label with<br />
• tabSpec.setIndicator("Some Text", tabIcon);
Option 2: Two Images<br />
(Normal and Selected)<br />
• Pros<br />
– Looks better<br />
• Cons<br />
– More work<br />
• Approach<br />
– Put image files in<br />
• res/drawable/some_icon_normal.png and<br />
• res/drawable/some_icon_selected.png<br />
– Make XML file (next page)<br />
• res/drawable/some_icon.xml<br />
– Refer to XML file with<br />
• Drawable tabIcon =<br />
resources.getDrawable(R.drawable.some_icon);<br />
– Put icon in tab label with<br />
• tabSpec.setIndicator("Some Text", tabIcon);<br />
436<br />
jeudi 26 janvier 12
XML Co<strong>de</strong> for Dual-Image Icon<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
437<br />
jeudi 26 janvier 12<br />
The file names of the two images are arbitrary. They need not end in _selected and _normal, although this<br />
can be a useful convention so that you know what the images are for.
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example:<br />
Invoking Loan Calculator<br />
(Each Tab Sends<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Example: Overview<br />
• Initial Activity<br />
–Has tabs that, when pressed, invoke the<br />
loan calculator with different data<br />
• Activity specified either with class name or URI<br />
– But either way, initial Activity must be in same project as new one<br />
• Data sent via either in extras Bundle or in URI<br />
• Approach<br />
439<br />
jeudi 26 janvier 12<br />
–Intents and data created in same way as before<br />
–Intent associated with tab via tabHost.setContent<br />
–Put entry for LoanCalculatorActivity in manifest<br />
• Same as shown previously
XML: Icon File<br />
(res/drawable/calculator.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
440<br />
jeudi 26 janvier 12
XML: Manifest File<br />
Action Declaration<br />
<br />
<br />
<br />
<br />
... <br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
441<br />
jeudi 26 janvier 12<br />
Unchanged from previous examples.
Java<br />
(TabbedActivity: Tab 1)<br />
public class TabbedActivity extends TabActivity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
Resources resources = getResources();<br />
TabHost host = getTabHost();<br />
Intent intent1 =<br />
new Intent(this, LoanCalculatorActivity.class);<br />
Bundle loanBundle1 =<br />
LoanBundler.makeLoanInfoBundle(100000, 7.5, 120);<br />
intent1.putExtras(loanBundle1);<br />
Drawable tabIcon =<br />
resources.getDrawable(R.drawable.calculator);<br />
TabSpec tab1Spec = host.newTabSpec("Tab One")<br />
.setIndicator("10 Year", tabIcon)<br />
.setContent(intent1);<br />
host.addTab(tab1Spec);<br />
442<br />
jeudi 26 janvier 12<br />
This first tab uses an Intent that specifies the Activity by class name.<br />
It sends data via an extras Bundle. Remin<strong>de</strong>r: there is no layout file when using TabActivity.
Java<br />
(TabbedActivity: Tab 2)<br />
443<br />
jeudi 26 janvier 12<br />
Uri uriTwentyYear =<br />
Uri.parse("loan://coreservlets.com/calc");<br />
Intent intent2 =<br />
new Intent(Intent.ACTION_VIEW, uriTwentyYear);<br />
Bundle loanBundle2 =<br />
LoanBundler.makeLoanInfoBundle(100000, 7.5, 240);<br />
intent2.putExtras(loanBundle2);<br />
tabIcon = resources.getDrawable(R.drawable.calculator);<br />
TabSpec tab2Spec = host.newTabSpec("Tab Two")<br />
.setIndicator("20 Year", tabIcon)<br />
.setContent(intent2);<br />
host.addTab(tab2Spec);<br />
This second tab uses an Intent that specifies the Activity with a URI.<br />
It sends data via an extras Bundle.
Java<br />
(TabbedActivity: Tab 3)<br />
444<br />
jeudi 26 janvier 12<br />
String baseAddress = "loan://coreservlets.com/calc";<br />
String address =<br />
String.format("%s?%s&%s&%s",<br />
baseAddress,<br />
"loanAmount=100000",<br />
"annualInterestRateInPercent=7.5",<br />
"loanPeriodInMonths=360");<br />
Uri uriThirtyYear = Uri.parse(address);<br />
Intent intent3 =<br />
new Intent(Intent.ACTION_VIEW, uriThirtyYear);<br />
tabIcon = resources.getDrawable(R.drawable.calculator);<br />
TabSpec tab3Spec = host.newTabSpec("Tab Three")<br />
.setIndicator("30 Year", tabIcon)<br />
.setContent(intent3);<br />
host.addTab(tab3Spec);<br />
This second tab uses an Intent that specifies the Activity with a URI.<br />
It sends data via parameters embed<strong>de</strong>d in the URI.
Example: Results<br />
445<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary<br />
• Java (extends TabActivity)<br />
TabHost host = getTabHost();<br />
Intent intent1= ...; // Refers to Activity in same project<br />
Drawable tabIcon = resources.getDrawable(R.drawable.some_icon);<br />
TabSpec tab1Spec = host.newTabSpec("Tab One")<br />
.setIndicator("Some Text", tabIcon)<br />
.setContent(intent1);<br />
host.addTab(tab1Spec);<br />
// Repeat for other tabs<br />
• Icon (res/drawable/some_icon.xml)<br />
<br />
<br />
<br />
<br />
<br />
447<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Localization and Resources<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Localization overview<br />
• Localization options<br />
–Language<br />
–Country/region language variations<br />
–Screen orientation<br />
–Display resolution<br />
–Others<br />
• Configuration qualifier prece<strong>de</strong>nce<br />
449<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Big I<strong>de</strong>a<br />
• Good news<br />
– Android’s use of resource files (res/layout/main.xml, res/values/<br />
strings.xml, etc.) simplifies GUI <strong>de</strong>velopment<br />
• Bad news<br />
– Descriptions in English won’t work in German<br />
– What fits in portrait orientation won’t fit in landscape<br />
– Images for high-<strong>de</strong>nsity screens are too large for low-<strong>de</strong>nsity ones<br />
• Solution<br />
– Make multiple layout and resource files<br />
• For different languages, orientations, etc.<br />
– Have Android automatically switch among or combine them<br />
• Notes<br />
– Localization sometimes called L10N (L, 10 letters, N)<br />
– Also sometimes called Internationalization (I18N)<br />
451<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Process<br />
• Make qualified versions of resource files<br />
– Find the settings that affect your application<br />
• Language, orientation, touchscreen type, dock mo<strong>de</strong>, etc.<br />
– Find qualifier names that correspond to each setting<br />
• Language: en, en-rUS, es, es-rMX, etc.<br />
• Screen orientation: port, land<br />
• Display <strong>de</strong>nsity: xhdpi, hdpi, mdpi, ldpi<br />
• Dock mo<strong>de</strong>: car, <strong>de</strong>sk<br />
• Etc.<br />
– Append qualifier names to fol<strong>de</strong>r names<br />
• res/values/strings.xml, res/values-es/strings.xml,<br />
res/values-es-rMX/main.xml<br />
• res/layout/main.xml, res/layout-land/main.xml<br />
• Load the resource normally<br />
– R.string.title, R.layout.main, etc.<br />
– Android will switch among layout files automatically<br />
– Android will combine values files automatically<br />
• More specific values will replace earlier ones<br />
452
jeudi 26 janvier 12<br />
Language<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Overview<br />
• I<strong>de</strong>a<br />
–Change the display based on the user’s language<br />
• Resources that typically change<br />
–Strings (in res/values, e.g., in res/values/strings.xml)<br />
–Images (in res/drawable – image file or XML file)<br />
–Colors (in res/values, e.g., in res/values/colors.xml)<br />
–Audio and vi<strong>de</strong>o (in res/raw)<br />
–Dimensions, arrays, and styles (in res/values, e.g., …/<br />
dimens.xml, …/arrays.xml, …/styles.xml)<br />
• Resources that do not usually change<br />
454<br />
jeudi 26 janvier 12<br />
–Layout files (in res/layout)<br />
• Changing layout based on language makes for hard-to-maintain<br />
apps. See best-practices sli<strong>de</strong>.
Steps<br />
• Make multiple fol<strong>de</strong>rs with language co<strong>de</strong>s<br />
– res/values, res/values-es, res/values-ja, etc.<br />
• Language co<strong>de</strong>s are specified by ISO 639-1<br />
– http://en.wikipedia.org/wiki/ISO_639-1<br />
• Define all strings in <strong>de</strong>fault fol<strong>de</strong>r<br />
– In res/values, <strong>de</strong>fine all names<br />
• Use the most common language<br />
– E.g., res/values/strings.xml (or other name in res/values)<br />
Apple<br />
Welcome!<br />
• Use similar approach for colors, images, etc.<br />
– Use res/values/ for all colors, dimensions, arrays, etc.<br />
– Use res/drawable for all image files<br />
– Use res/raw for all audio and vi<strong>de</strong>o files<br />
455<br />
jeudi 26 janvier 12
Steps (Continued)<br />
• In XML, refer to base string name<br />
– someAttribute="@string/company_name"<br />
– someAttribute="@ string/welcome_message"<br />
• No reference to fol<strong>de</strong>r or language.<br />
• Android will provi<strong>de</strong> the proper version automatically. It first loads values<br />
from res/values/strings.xml, then loads values from res/values-es/<br />
strings.xml. Any names in second file that are common to first file are<br />
replaced.<br />
• In Java, refer to base string name<br />
– getString(R.string.company_name)<br />
– getString(R.string.welcome_message)<br />
• No reference to fol<strong>de</strong>r or language. Same process as above.<br />
• Use similar approach for other resources<br />
– XML: @drawable/flag, @color/<strong>de</strong>fault_foreground, etc.<br />
– Java: R.drawable.flag, R.color.<strong>de</strong>fault_foreground, etc.<br />
457<br />
jeudi 26 janvier 12
How User Changes Device<br />
Language<br />
• On phone (or other physical Android <strong>de</strong>vice)<br />
458<br />
jeudi 26 janvier 12<br />
–Go to home screen, press Menu button, select Settings<br />
• (Most people also have the Settings app on <strong>de</strong>sktop)<br />
–Choose Language and Keyboard<br />
–Choose Select locale at the top<br />
• Most phones will have a very<br />
limited number of choices,<br />
based on what <strong>de</strong>vice<br />
manufacturer supports<br />
– Android cannot (easily) use<br />
localization within apps unless<br />
entire OS supports that language.<br />
Major Android failing.<br />
– But, see upcoming sli<strong>de</strong>s on<br />
programmatic Locale changes.
How User Changes Device<br />
Language<br />
• On emulator<br />
459<br />
jeudi 26 janvier 12<br />
–Option 1: use same approach as<br />
above<br />
• You will have a limited number of<br />
choices, based on what was<br />
installed in your Android SDK image.<br />
But, it will almost certainly be a<br />
bigger set than the real phone.<br />
–Option 2: use Custom Locale app<br />
on app screen<br />
• If Locale you want is not there, add it<br />
(even regional ones)<br />
• Long-press the Locale to choose it<br />
To go to app screen, go to home<br />
screen and press this.
Example: The Android Resort<br />
• I<strong>de</strong>a<br />
–Make an app that advertises a luxury resort where visitors can<br />
sit insi<strong>de</strong> all day and play with their smart phones<br />
• Approach<br />
460<br />
jeudi 26 janvier 12<br />
–res/values/strings.xml <strong>de</strong>fines<br />
• resort_name, welcome, our, pool, reserve, confirmed<br />
–res/values-es/strings.xml <strong>de</strong>fines<br />
• welcome, our, pool, reserve, confirmed<br />
– Does not re<strong>de</strong>fine resort_name<br />
–Also uses dimensions, colors, images, and layout files<br />
• But these do not change based on language, so localized<br />
versions are not shown until a later example
Strings File: English/Other<br />
(res/values/strings.xml)<br />
<br />
<br />
AndroidResort.com<br />
Welcome to <br />
Our <br />
swimming pool<br />
Reserve Now!<br />
Registration Confirmed<br />
<br />
461<br />
jeudi 26 janvier 12<br />
Remin<strong>de</strong>r from intents lecture:   is a non-breaking space.<br />
Android does not preserve whitespace at the beginning and end of<br />
strings in resource files.
Strings File: Spanish<br />
(res/values-es/strings.xml)<br />
<br />
<br />
Bienvenido a <br />
Nuestra <br />
piscina<br />
¡Reserva Ahora!<br />
Registro Confirmado<br />
<br />
462<br />
jeudi 26 janvier 12<br />
Note that there is not an entry for resort_name.<br />
The value from res/values/strings.xml carries over.
Layout File res/layout/main.xml<br />
(No Language-Based Versions)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
463<br />
jeudi 26 janvier 12
Manifest File<br />
(No Language-Based Versions)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
464<br />
jeudi 26 janvier 12
Java Co<strong>de</strong><br />
public class AndroidResortActivity extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
}<br />
}<br />
465<br />
jeudi 26 janvier 12<br />
public void confirmRegistration(View clickedButton) {<br />
String message = getString(R.string.confirmed);<br />
showToast(message);<br />
}<br />
private void showToast(String text) {<br />
Toast.makeText(this, text, Toast.LENGTH_LONG).show();<br />
}
Project Layout<br />
466<br />
jeudi 26 janvier 12<br />
Uses the named strings via getString(R.string.string_name). Uses same<br />
syntax regardless of whether the string came from values/strings.xml or<br />
was overrid<strong>de</strong>n in values-es/strings.xml<br />
Uses the named strings via @string/string_name. Uses same syntax regardless of<br />
whether the string came from values/strings.xml or was overrid<strong>de</strong>n in values-es/<br />
strings.xml<br />
Defines all named strings. Applies to all languages except Spanish, and even one of<br />
the names applies to Spanish, since the Spanish version does not overri<strong>de</strong><br />
resort_name.<br />
Overri<strong>de</strong>s the named strings that are different in Spanish.
Results: English<br />
467<br />
jeudi 26 janvier 12<br />
res/values/strings.xml<br />
• resort_name<br />
• welcome<br />
• our<br />
• pool<br />
• reserve<br />
• confirmed<br />
This is the result not just for English, but for any language other than Spanish.
Results: Spanish<br />
468<br />
jeudi 26 janvier 12<br />
res/values/strings.xml<br />
• resort_name<br />
res/values-es/strings.xml<br />
• welcome<br />
• our<br />
• pool<br />
• reserve<br />
• confirmed
Best Practices<br />
• Provi<strong>de</strong> unlocalized <strong>de</strong>faults for all values<br />
–So if Locale is unexpected, it displays in <strong>de</strong>fault language<br />
• E.g., if English is main language, use res/values, not res/valuesen.<br />
Also, test your app in unsupported Locale.<br />
• Use graphical layout editor for testing<br />
–For layout file, it lets you interactively change language,<br />
screen orientation, display resolution, and more<br />
• Avoid changing layouts based on language<br />
469<br />
jeudi 26 janvier 12<br />
–Might be necessary in some cases (e.g., US English asks for<br />
given name first and family name second, whereas Indian<br />
English asks for them in opposite or<strong>de</strong>r). However, makes for<br />
hard-to-maintain co<strong>de</strong>.<br />
• Consi<strong>de</strong>r putting the logic in Java co<strong>de</strong> instead
Graphical Layout Editor in<br />
Eclipse (Editing main.xml)<br />
470<br />
jeudi 26 janvier 12<br />
Changing display resolution<br />
Changing screen orientation<br />
Changing language (Eclipse will list all languages your<br />
app supports, based on your fol<strong>de</strong>r names)<br />
Also lets you change dock<br />
mo<strong>de</strong>, day/night mo<strong>de</strong>, style<br />
(theme), and Android version.
Changing the Language<br />
Programmatically<br />
• Letting user change Locale<br />
– Pros<br />
• Expected/recommen<strong>de</strong>d Android approach<br />
• All localization works gracefully<br />
– Cons<br />
• Can only use languages that <strong>de</strong>vice manufacturer supports for the<br />
entire OS<br />
• Requires user to take several steps they might not know<br />
• Changing Locale in your co<strong>de</strong><br />
– Pros<br />
• Can use any language you want<br />
• Can let user set language in app with simple button<br />
– Cons<br />
• Not expected/recommen<strong>de</strong>d approach<br />
• Settings do not live across app restarts (including rotations!), so<br />
requires you to remember and reuse it.<br />
471<br />
jeudi 26 janvier 12
Changing the Language<br />
Programmatically: Co<strong>de</strong><br />
• Steps<br />
Locale locale = new Locale("es"); // Language co<strong>de</strong><br />
Locale.setDefault(locale);<br />
Configuration config = new Configuration();<br />
config.locale = locale;<br />
context.getResources().updateConfiguration(config,<br />
–context above is reference to the main Activity<br />
• More <strong>de</strong>tails<br />
472<br />
jeudi 26 janvier 12<br />
–http://adrianvintu.com/blogengine/post/<br />
Force-Locale-on-Android.aspx<br />
null);
jeudi 26 janvier 12<br />
Region<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
I<strong>de</strong>a<br />
• Values can be specific to region<br />
– Not only to general language<br />
– Examples<br />
• Words<br />
– US English: garbage truck<br />
– Australian English: rubbish lorry<br />
• Images<br />
– Flag of the country<br />
• Colors<br />
– Colors matching flag<br />
• Audio files<br />
– US English: Yankee Doodle<br />
– Australian English: Waltzing Matilda<br />
• Good news<br />
– Android lets you <strong>de</strong>fine res/values-en-au, etc.<br />
• Bad news<br />
– Most phones support few or no regional settings<br />
474<br />
jeudi 26 janvier 12
Steps<br />
• Put <strong>de</strong>fault values in res/values<br />
–As before. List all the names<br />
• Put general lang. values in res/values-xx<br />
–Where xx is ISO 639-1 language co<strong>de</strong> as before<br />
–List only the names that change from the <strong>de</strong>fault language<br />
• Put regional values in res/values-xx-rYY<br />
–Where xx is the language co<strong>de</strong> and YY is the country co<strong>de</strong><br />
(case insensitive). Note the “r” for “region”.<br />
• Co<strong>de</strong>s are specified by ISO 3166-1<br />
– http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3<br />
–List only the names that change from the base language<br />
• Process<br />
475<br />
jeudi 26 janvier 12<br />
–Android will load from most general to most specific
Example: The Android Resort<br />
• I<strong>de</strong>a<br />
–Add support for Mexican Spanish, which uses “alberca”<br />
instead of “piscina” for “swimming pool”.<br />
• Approach<br />
476<br />
jeudi 26 janvier 12<br />
–res/values/strings.xml <strong>de</strong>fines<br />
• resort_name, welcome, our, pool, reserve, confirmed<br />
–res/values-es/strings.xml <strong>de</strong>fines<br />
• welcome, our, pool, reserve, confirmed<br />
–res/values-es-rMX/strings.xml <strong>de</strong>fines<br />
• pool
Strings File: English/Other<br />
(res/values/strings.xml)<br />
<br />
<br />
AndroidResort.com<br />
Welcome to <br />
Our <br />
swimming pool<br />
Reserve Now!<br />
Registration Confirmed<br />
<br />
477<br />
jeudi 26 janvier 12
Strings File: General Spanish<br />
(res/values-es/strings.xml)<br />
<br />
<br />
Bienvenido a <br />
Nuestra <br />
piscina<br />
¡Reserva Ahora!<br />
Registro Confirmado<br />
<br />
478<br />
jeudi 26 janvier 12
Strings File: Mexican Spanish<br />
(res/values-es-rMX/strings.xml)<br />
<br />
<br />
alberca<br />
<br />
479<br />
jeudi 26 janvier 12
Project Layout<br />
480<br />
jeudi 26 janvier 12<br />
Uses the named strings via getString(R.string.string_name). Uses same<br />
syntax regardless of whether the string came from values/strings.xml or<br />
was overrid<strong>de</strong>n in values-es/strings.xml or values-es-rMX/strings.xml.<br />
Uses the named strings via @string/string_name. Uses same syntax regardless of<br />
whether the string came from values/strings.xml or was overrid<strong>de</strong>n in values-es/<br />
strings.xml or values-es-rMX/strings.xml.<br />
Defines all named strings. Applies to all languages except Spanish, and even one of<br />
the names applies to Spanish, since the Spanish versions do not overri<strong>de</strong><br />
resort_name.<br />
Overri<strong>de</strong>s the named strings that are different in Spanish.<br />
Overri<strong>de</strong>s the named strings that are different in Mexican Spanish from in<br />
general Spanish.
Results<br />
481<br />
jeudi 26 janvier 12<br />
Any language other than Spanish General Spanish Mexican Spanish
jeudi 26 janvier 12<br />
Screen Orientation<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Overview<br />
• I<strong>de</strong>a<br />
–Change the display based on whether the <strong>de</strong>vice is being held<br />
in portrait or landscape mo<strong>de</strong>.<br />
• Resources that typically change<br />
–Layout files (in res/layout)<br />
–Images (in res/drawable – image file or XML file)<br />
–Dimensions (in res/values, e.g., …/dimens.xml)<br />
–Vi<strong>de</strong>o (in res/raw)<br />
• Resources that do not usually change<br />
483<br />
jeudi 26 janvier 12<br />
–Strings (in res/values, e.g., in res/values/strings.xml)<br />
–Colors (in res/values, e.g., in res/values/colors.xml)<br />
–Audio (in res/raw)
Steps<br />
• Make two fol<strong>de</strong>rs: <strong>de</strong>fault and landscape<br />
–res/layout and res/layout-land<br />
• You can do layout-port, but more common to use <strong>de</strong>fault<br />
• Define different layouts (of same name) in<br />
each<br />
–For portrait mo<strong>de</strong><br />
• res/layout/main.xml (and maybe other names)<br />
–For landscape mo<strong>de</strong><br />
• res/layout-land/main.xml (and maybe other names)<br />
• Use similar approach for dimensions, images,<br />
etc.<br />
–Use res/values/ and res/drawable for portrait mo<strong>de</strong> and for<br />
things that are the same in both orientations.<br />
484<br />
jeudi 26 janvier 12<br />
–Overri<strong>de</strong> in res/values-land and res/drawable-land
Steps (Continued)<br />
• In XML, refer to base dimensions or images<br />
–textSize="@dimen/heading_size"<br />
–src="@ drawable/some_image"<br />
• No reference to fol<strong>de</strong>r or orientation. Android handles.<br />
• In Java, refer to base layout name<br />
485<br />
jeudi 26 janvier 12<br />
–setContentView(R.layout.main)<br />
• Android will provi<strong>de</strong> the proper version automatically. For layout<br />
files, only one version applies. For values files, names are<br />
combined as before, with later values overriding earlier values of<br />
the same name.
Prece<strong>de</strong>nce of Fol<strong>de</strong>r Names<br />
• I<strong>de</strong>a<br />
– Many fol<strong>de</strong>rs with a single qualifier could apply (values, values-es,<br />
values-land, etc.).<br />
– You can also combine the names (e.g., values-es-land)<br />
• Language must be first, so use values-es-land, not values-land-es<br />
– So, which entries win?<br />
• Layout files and drawable files<br />
– Only one file applies. Language entries win over screen orientation, so if<br />
there is layout-es and layout-land, and you are in both Spanish and<br />
landscape, layout-es wins<br />
• But, remember advice to avoid language-based layouts<br />
• Values files<br />
– Many files may apply. They are loa<strong>de</strong>d from least specific to most<br />
specific, and later values overri<strong>de</strong> earlier ones of the same name.<br />
Language is more specific than orientation.<br />
486<br />
jeudi 26 janvier 12
How User Changes Screen<br />
Orientation<br />
• On phone (or other Android <strong>de</strong>vice)<br />
–Physically rotate the <strong>de</strong>vice<br />
• On emulator<br />
–Hit Control-F12 or<br />
–Hit 9 on the number keypad (Num Lock must be off)<br />
• In visual layout editor in Eclipse<br />
487<br />
jeudi 26 janvier 12<br />
–Choose Portrait or Landscape from the second combobox<br />
above the display
Example: The Android Resort<br />
• I<strong>de</strong>a<br />
–Use two layouts: one for portrait and one for landscape<br />
–Change font sizes for heading <strong>de</strong>pending on orientation<br />
–Keep support for English and Spanish<br />
• Approach<br />
488<br />
jeudi 26 janvier 12<br />
–res/layout/main.xml <strong>de</strong>fines layout for portrait mo<strong>de</strong><br />
–res/layout-land/main.xml <strong>de</strong>fines layout for landscape<br />
–res/values/dimens.xml <strong>de</strong>fines font size for portrait<br />
–res/values-land/dimens.xml <strong>de</strong>fines size for landscape<br />
–res/values, res/values-es, and res/values-es-rMX <strong>de</strong>fine strings<br />
and colors as shown previously
Layout File: Portrait Mo<strong>de</strong><br />
(res/layout/main.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
489<br />
jeudi 26 janvier 12
Layout File: Landscape Mo<strong>de</strong><br />
(res/layout-land/main.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
490<br />
jeudi 26 janvier 12<br />
Recall that horizontal is the <strong>de</strong>fault orientation.
Dimensions File: Portrait Mo<strong>de</strong><br />
(res/values/dimens.xml)<br />
<br />
<br />
32dp<br />
22dp<br />
<br />
491<br />
jeudi 26 janvier 12
Dimensions File: Landscape<br />
(res/values-land/dimens.xml)<br />
<br />
<br />
26dp<br />
24dp<br />
<br />
492<br />
jeudi 26 janvier 12
Project Layout<br />
493<br />
jeudi 26 janvier 12<br />
Defines the layout for portrait mo<strong>de</strong>. Uses @dimen/heading_size and @dimen/<br />
body_size, which are <strong>de</strong>fined in res/values/dimens.xml<br />
Defines the layout for landscape mo<strong>de</strong>. Uses @dimen/heading_size and @dimen/<br />
body_size, which are <strong>de</strong>fined in res/values-land/dimens.xml<br />
Defines heading_size and body_size for use in portrait mo<strong>de</strong>.<br />
Defines heading_size and body_size for use in landscape mo<strong>de</strong>.
Results: English<br />
(Really Non-Spanish)<br />
494<br />
jeudi 26 janvier 12
Results: General Spanish<br />
495<br />
jeudi 26 janvier 12
Results: Mexican Spanish<br />
496<br />
jeudi 26 janvier 12
Preventing Screen Rotations<br />
• Issue<br />
–Screen rotations usually require a new layout<br />
–They also cause the app to be shutdown and restarted<br />
• Handling this will be discussed in the next lecture<br />
• Problem<br />
–What if you do not have landscape layout?<br />
–Or have not yet handled shutdown and restart?<br />
• Solution<br />
497<br />
jeudi 26 janvier 12<br />
–Put an entry in AndroidManifest.xml saying that app runs<br />
only in portrait mo<strong>de</strong> (or only in landscape mo<strong>de</strong>)<br />
Example: Screen from Widgets<br />
Lecture (Manifest File)<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
498<br />
jeudi 26 janvier 12
Example: Results<br />
(in Landscape Mo<strong>de</strong>)<br />
499<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Display Resolution<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Overview<br />
• I<strong>de</strong>a<br />
–Change images based on the resolution of the display<br />
• Resources that typically change<br />
–Images (in res/drawable – image file or XML file)<br />
–Vi<strong>de</strong>o (in res/raw)<br />
• Resources that do not usually change<br />
501<br />
jeudi 26 janvier 12<br />
–Dimensions<br />
• If you use xxdp, then it will scale to screen resolution<br />
– There are also small, normal, large, and xlarge qualifiers for screen size. Even<br />
with xxdp, you might want to adapt to those<br />
• But if you use yypx or zzin or aamm, then you need to change<br />
the dimensions to match the resolution<br />
–Layout files, strings, colors, audio, etc.
Common Approaches<br />
• Alternative 1: Default plus two others<br />
– drawable<br />
• Put images for high-res and extra-high-res (dots-per-inch) here<br />
– drawable-mdpi<br />
• Put images for medium-res (dots-per-inch) here<br />
– drawable-ldpi<br />
• Put images for low-res (dots-per-inch) here<br />
• Alternative 2: Three res-specific fol<strong>de</strong>rs<br />
– drawable-hdpi<br />
• Put images for high-res and extra-high-res (dots-per-inch) here<br />
– drawable-mdpi<br />
• Put images for medium-res (dots-per-inch) here<br />
– drawable-ldpi<br />
• Put images for low-res (dots-per-inch) here<br />
502<br />
jeudi 26 janvier 12
Meanings of Resolution Qualifiers<br />
• xhdpi (extra-high dpi)<br />
–320 dots per inch<br />
–But, Android uses best match, so if you put images in<br />
drawable-hdpi and it is extra-high, images are still used.<br />
• Another common option is to use a single set of images for both<br />
extra-high and high, and put them in drawable<br />
• hdpi (high dpi)<br />
–240 dots per inch<br />
• mdpi (medium dpi)<br />
–160 dots per inch<br />
• ldpi (low dpi)<br />
503<br />
jeudi 26 janvier 12<br />
–120 dots per inch
Best Practices<br />
• For small icons (e.g., for ImageButton)<br />
–Use multiple versions<br />
–Realize that the size will be slightly different on different<br />
displays, so leave enough room to compensate<br />
• For larger images (e.g., for ImageView)<br />
504<br />
jeudi 26 janvier 12<br />
–Use multiple versions<br />
–Scale the image if it is larger than the available space<br />
Prece<strong>de</strong>nce of Fol<strong>de</strong>r Names<br />
• I<strong>de</strong>a<br />
– You may have many fol<strong>de</strong>rs that apply<br />
• drawable, drawable-mdpi, drawable-es, drawable-es-land-hdpi…<br />
– So, which entries win?<br />
• Prece<strong>de</strong>nce rules<br />
505<br />
jeudi 26 janvier 12<br />
– Language is highest prece<strong>de</strong>nce<br />
• drawable-es wins over drawable-land or drawable-mdpi<br />
– Orientation is second highest<br />
• drawable-land wins over drawable-hdpi<br />
– Density is last (of these three)<br />
• But, try to chain the qualifiers so there is never a conflict.<br />
– drawable-land-hdpi, drawable-land-mdpi, etc.
Example: The Android Resort<br />
• I<strong>de</strong>a<br />
–Have three versions of the swimming pool image: for low,<br />
medium, and high (or extra-high) resolution <strong>de</strong>vices<br />
• Approach<br />
506<br />
jeudi 26 janvier 12<br />
–drawable/android_resort_pool.jpg<br />
• For high-res or extra-high-res <strong>de</strong>vices<br />
–drawable-mdpi/android_resort_pool.jpg<br />
• For medium-res <strong>de</strong>vices<br />
–drawable-ldpi/android_resort_pool.jpg<br />
• For low-res <strong>de</strong>vices<br />
–Scale the image so that if it is still too big, it will not be<br />
cropped
Results (Choosing Different<br />
Densities in Visual Editor)<br />
507<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Configuration Types<br />
• Most common qualifiers (in or<strong>de</strong>r of prece<strong>de</strong>nce)<br />
– Language and region<br />
• es, es-rMX, etc.<br />
– Screen size<br />
• small, normal, large, xlarge<br />
– Orientation<br />
• port, land<br />
– Resolution (<strong>de</strong>nsity)<br />
• ldpi, mdpi, hdpi, xhdpi<br />
– Touchscreen type<br />
• notouch, stylus, finger<br />
– Full list<br />
• http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/topics/resources/<br />
providing-resources.html<br />
• Using multiple qualifiers<br />
– Or<strong>de</strong>r of qualifiers must match prece<strong>de</strong>nce or<strong>de</strong>r above<br />
• values-es-port-ldpi, not values-es-ldpi-port or values-port-es-ldpi<br />
509<br />
jeudi 26 janvier 12
More Reading<br />
• Developer’s Gui<strong>de</strong>: Localization<br />
–http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/topics/resources/<br />
localization.html<br />
• Developer’s Gui<strong>de</strong>: Application Resources<br />
–http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/topics/resources/<br />
• Tutorial: Hello L10N<br />
–http://<strong>de</strong>veloper.android.com/resources/tutorials/<br />
localization/in<strong>de</strong>x.html<br />
• Chapter: Localization<br />
510<br />
jeudi 26 janvier 12<br />
–From Android in Action by Ableson et al
Summary<br />
• Language<br />
–Provi<strong>de</strong> multiple versions of strings file<br />
• Maybe images, colors, and sounds as well<br />
• Default fol<strong>de</strong>r should provi<strong>de</strong> values for all names<br />
• Screen orientation<br />
–Provi<strong>de</strong> multiple versions of layout files<br />
• Maybe dimension files and images as well<br />
• Screen <strong>de</strong>nsity<br />
–Provi<strong>de</strong> multiple versions of images (drawable files)<br />
• Maybe vi<strong>de</strong>os and dimension files as well<br />
• Best practices<br />
511<br />
jeudi 26 janvier 12<br />
–Test in all combinations, esp. unexpected languages<br />
–Use Eclipse graphical layout editor for initial testing
jeudi 26 janvier 12<br />
Handling Screen Rotations and<br />
Other App Restarts<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Motivation<br />
• Saving data<br />
• The Bundle class<br />
• Retrieving data<br />
• Activity lifecycle<br />
513<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Big I<strong>de</strong>a<br />
• Android can shut down and restart your app<br />
– When you rotate the screen<br />
– When you change languages<br />
– When app is in background and Android is short on memory<br />
– When you hit the Back button<br />
• Problem<br />
– You risk losing user changes<br />
• Solution<br />
– Save data in a Bundle in onSaveInstanceState<br />
– Read data out of Bundle in onRestoreInstanceState<br />
(or in onCreate)<br />
• Does not handle Back button scenario.<br />
App restarts from scratch with no saved data in that case.<br />
515<br />
jeudi 26 janvier 12
Remin<strong>de</strong>r:<br />
Preventing Screen Rotations<br />
• Issue<br />
–Screen rotations usually require a new layout<br />
–They also cause the app to be shutdown and restarted<br />
• Handling this is the topic of this lecture<br />
• Problem<br />
–What if you do not have landscape layout?<br />
–Or have not yet handled shutdown and restart?<br />
• Solution<br />
516<br />
jeudi 26 janvier 12<br />
–Put an entry in AndroidManifest.xml saying that app runs<br />
only in portrait mo<strong>de</strong> (or only in landscape mo<strong>de</strong>).<br />
jeudi 26 janvier 12<br />
Steps<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Summary: Saving Data<br />
• Overri<strong>de</strong> onSaveInstanceState<br />
– And pass the Bundle to the superclass method<br />
protected void onSaveInstanceState(Bundle outState) {<br />
super.onSaveInstanceState(outState);<br />
outState.putBlah(someData);<br />
}<br />
• Called<br />
– When user rotates screen<br />
– When user changes language<br />
– When app is hid<strong>de</strong>n and Android needs the memory<br />
• Not called<br />
– When user hits Back button<br />
• Note<br />
– Superclass method automatically stores state of GUI widgets (EditText<br />
data, CheckBox state, etc.)<br />
518<br />
jeudi 26 janvier 12
Summary: Restoring Data<br />
• Overri<strong>de</strong> onRestoreInstanceState<br />
–Pass Bundle to superclass method<br />
–Look for data by name, check for null, use the data<br />
protected void onRestoreInstanceState(Bundle savedInstanceState) {<br />
super.onRestoreInstanceState(savedInstanceState);<br />
SomeType data = savedInstanceState.getBlah(key);<br />
if (data != null) { doSomethingWith(data); }<br />
}<br />
• Called<br />
–Any time app is restarted after onSaveInstanceState<br />
• Note<br />
519<br />
jeudi 26 janvier 12<br />
–The same Bundle is passed to onCreate.<br />
–Superclass method automatically restores widget state
The Bundle Class: Details<br />
• Putting data in a Bundle<br />
– putBoolean, putBooleanArray, putDouble, putDoubleArray,<br />
putString, putStringArray, etc.<br />
• These all take keys and values as arguments.<br />
The keys must be Strings. The values must be of the standard types<br />
(int, double, etc.) or array of them.<br />
– putSerializable, putParceleable<br />
• Lets you store custom objects. Note that ArrayList and most other<br />
builtin Java types are already Serializable<br />
• Retrieving data from a Bundle<br />
– getBoolean, getBooleanArray, getDouble, getDoubleArray,<br />
getString, getStringArray, etc.<br />
• No typecast required on retrieval. Numbers are 0 if no match.<br />
– getSerializable, getParceleable<br />
• Typecast required on retrieval. Values are null if no match.<br />
520<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Example<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Loan Payment Comparisons<br />
• I<strong>de</strong>a<br />
–User can enter various interest rates to compare the resultant<br />
monthly and total payments for a $100K,<br />
30 year, fixed-rate loan<br />
–Different layouts for portrait and landscape mo<strong>de</strong>s<br />
–Uses the PaymentInfo class that was shown in the first Intents<br />
lecture<br />
• Approach<br />
522<br />
jeudi 26 janvier 12<br />
–Keep an ArrayList of PaymentInfo<br />
• Also put results in a TableView<br />
–In onSaveInstanceState, store the ArrayList<br />
–In onRestoreInstanceState, retrieve the ArrayList<br />
• Also put results in a TableView
Layout File: Portrait Mo<strong>de</strong><br />
(res/layout/main.xml)<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
(Has heading and divi<strong>de</strong>r, but no body rows.)<br />
<br />
<br />
523<br />
jeudi 26 janvier 12
Layout File: Landscape Mo<strong>de</strong><br />
(res/layout-land/main.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
<br />
(Has heading and divi<strong>de</strong>r, but no body rows.)<br />
<br />
<br />
524<br />
jeudi 26 janvier 12
Values Files<br />
• res/values/strings.xml<br />
–Defines intro text, prompt, table headings,<br />
and button label.<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/dimens.xml<br />
–Gives font sizes.<br />
• Used in portrait mo<strong>de</strong>.<br />
• res/values-land/dimens.xml<br />
525<br />
jeudi 26 janvier 12<br />
–Gives font sizes.<br />
• Used in landscape mo<strong>de</strong>.
Core Java Co<strong>de</strong><br />
public class RotationsActivity extends Activity {<br />
private final static double LOAN_AMOUNT = 100000;<br />
private final static long LOAN_PERIOD = 360; // In months<br />
private TableLayout mPaymentsTable;<br />
private EditText mInterestRateField;<br />
private float mTableSize;<br />
private ArrayList mRowData =<br />
new ArrayList();<br />
526<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
mPaymentsTable = (TableLayout)findViewById(R.id.payment_table);<br />
mInterestRateField =<br />
(EditText)findViewById(R.id.interest_rate_field);<br />
Resources resources = getResources();<br />
mTableSize = resources.getDimension(R.dimen.table_body_size);<br />
}<br />
Looks up the ID of the table so that it can later programmatically add rows to it. Note that the<br />
PaymentInfo data is <strong>de</strong>clared as ArrayList instead of List. This is because we will later store it in a<br />
Bundle, and ArrayList is Serializable whereas List is not.
Core Java Co<strong>de</strong> (Continued)<br />
527<br />
jeudi 26 janvier 12<br />
// Attached to the Button via the android:onClick attribute<br />
public void addComparisonRow(View clickedButton) {<br />
double interestRate = 5.0;<br />
try {<br />
interestRate = Double.parseDouble<br />
(mInterestRateField.getText().toString());<br />
} catch(Exception e) {}<br />
PaymentInfo info =<br />
new PaymentInfo(LOAN_AMOUNT, interestRate, LOAN_PERIOD);<br />
mRowData.add(info);<br />
addRow(info);<br />
mInterestRateField.setText("");<br />
}<br />
Reads the textfield value, converts to a number (5.0 <strong>de</strong>fault if field is empty or value is illegal), computes payment info,<br />
stores payment info in an ArrayList, then calls co<strong>de</strong> to add data to bottom of table.
Core Java Co<strong>de</strong> (Continued)<br />
528<br />
jeudi 26 janvier 12<br />
private void addRow(PaymentInfo info) {<br />
TableRow row = new TableRow(this);<br />
row.addView(makeColumn<br />
(info.getFormattedAnnualInterestRateInPercent()));<br />
row.addView(makeColumn(info.getFormattedMonthlyPayment()));<br />
row.addView(makeColumn(info.getFormattedTotalPayments()));<br />
mPaymentsTable.addView(row);<br />
}<br />
private TextView makeColumn(String text) {<br />
TextView col = new TextView(this);<br />
col.setGravity(Gravity.RIGHT);<br />
col.setTextSize(mTableSize);<br />
col.setText(text);<br />
return(col);<br />
}<br />
Creates a TableRow and inserts it into bottom of TableView.
Results (Without Saving State)<br />
529<br />
jeudi 26 janvier 12<br />
User enters some interest rates to<br />
get this result<br />
After entering the data as on the left,<br />
user rotates the screen. Data is lost!
Java Co<strong>de</strong>: Saving State<br />
530<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
protected void onSaveInstanceState(Bundle outState) {<br />
super.onSaveInstanceState(outState);<br />
outState.putSerializable("rowData", mRowData);<br />
}<br />
ArrayList is already Serializable. But, I had to make PaymentInfo (the data insi<strong>de</strong>) Serializable as well.
Java Co<strong>de</strong>: Saving State<br />
531<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
protected void onRestoreInstanceState(Bundle savedInstanceState) {<br />
super.onRestoreInstanceState(savedInstanceState);<br />
@SuppressWarnings("unchecked")<br />
ArrayList rowData =<br />
(ArrayList)<br />
savedInstanceState.getSerializable("rowData");<br />
if (rowData != null) {<br />
mRowData = rowData;<br />
for(PaymentInfo info: rowData) {<br />
addRow(info);<br />
}<br />
}<br />
}<br />
Since generics are implemented by erasure (all work done at compile time, no work done at run time), casting to ArrayList will<br />
give a warning that Java cannot verify that the list contains only Blahs. So, suppress that warning.
Java Co<strong>de</strong>: PaymentInfo<br />
public class PaymentInfo implements Serializable {<br />
private final double mLoanAmount,<br />
mAnnualInterestRateInPercent,<br />
mMonthlyPayment, mTotalPayments;<br />
private final long mLoanPeriodInMonths;<br />
private final String mCurrencySymbol;<br />
}<br />
532<br />
jeudi 26 janvier 12<br />
// Calculates and stores monthly payment and total payments<br />
// Has methods to print out values with nice formatting<br />
Custom data stored in a Bundle must be Serializable or Parceleable.
Results (Saving State)<br />
533<br />
jeudi 26 janvier 12<br />
User enters some interest rates to<br />
get this result<br />
After entering the data as on the left, user<br />
rotates the screen. Data is preserved!
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
More Lifecycle Events<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Overview<br />
• I<strong>de</strong>a<br />
–You can respond to situations other than app being killed and<br />
app being restarted<br />
• Situations<br />
535<br />
jeudi 26 janvier 12<br />
–Another Activity partially obscures Activity<br />
• Use onPause<br />
–Activity is no longer visible at all<br />
• Use onStop<br />
–A stopped Activity is restarted<br />
• Use onStart (every time including first) or<br />
onRestart (every time except first)<br />
–An Activity is killed for good (no saved state Bundle)<br />
• Use onDestroy
Lifecycle Summary<br />
onSaveInstanceState is called<br />
here<br />
536<br />
jeudi 26 janvier 12<br />
If state was saved before,<br />
onRestoreInstanceState is<br />
called here<br />
Diagram taken from top of http://<strong>de</strong>veloper.android.com/reference/android/app/<br />
Activity.html
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
More Reading<br />
• JavaDoc: Activity<br />
–http://<strong>de</strong>veloper.android.com/reference/android/app/<br />
Activity.html<br />
• Introductory parts give lots of <strong>de</strong>tails<br />
• Chapters<br />
538<br />
jeudi 26 janvier 12<br />
–Handling Activity Lifecycle Events and<br />
–Handling Rotation<br />
• From The Busy Co<strong>de</strong>r’s Gui<strong>de</strong> to Android Development<br />
by Mark Murphy.<br />
– http://commonsware.com/Android/
Summary<br />
• Save data in onSaveInstanceState<br />
–Can put individual pieces of data in the Bundle, or can add a<br />
composite data structure.<br />
–Custom classes must implement Serializable or Parceleable<br />
• Load data in onRestoreInstanceState<br />
or in onCreate<br />
539<br />
jeudi 26 janvier 12<br />
–Look in Bundle for property of given name<br />
–For Object types, check for null<br />
–For number types, check for 0
jeudi 26 janvier 12<br />
Network Programming:<br />
Part I (General Techniques)<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Part I (this section): general networking<br />
– Socket basics<br />
– Requesting Internet permission<br />
– Example: NIST atomic time<br />
– Asi<strong>de</strong>: simple String formatting and parsing<br />
– Example: FTP welcome messages<br />
– Example: validating URLs with HEAD<br />
• Part II (next section): HTTP-specific approaches<br />
– HttpURLConnection<br />
– HttpClient<br />
– Examples: Searching Web pages<br />
– Using JSON<br />
– Example: remote loan calculations<br />
– Example: Google translation services<br />
541<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Big I<strong>de</strong>a<br />
• Many ways to communicate with a server<br />
543<br />
jeudi 26 janvier 12<br />
–Socket class<br />
• Lets you do general-purpose network programming<br />
– Same as with <strong>de</strong>sktop Java programming<br />
–HttpURLConnection<br />
• Simplifies connections to HTTP servers<br />
– Same as with <strong>de</strong>sktop Java programming<br />
–HttpClient<br />
• Simplest way to download entire content of a URL<br />
– Not standard in Java SE, but standard in Android<br />
–JSONObject<br />
• Simplifies creation and parsing of JSON data<br />
– Not standard in Java SE, but standard in Android
jeudi 26 janvier 12<br />
Socket Basics<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Steps for Talking to Server<br />
1. Create a Socket object<br />
Socket client = new Socket("hostname", portNumber);<br />
2. Create output stream to send data to the Socket<br />
// Last arg of true means autoflush -- flush stream<br />
// when println is called<br />
PrintWriter out =<br />
new PrintWriter(client.getOutputStream(), true);<br />
3. Create input stream to read response from server<br />
545<br />
jeudi 26 janvier 12<br />
BufferedRea<strong>de</strong>r in =<br />
new BufferedRea<strong>de</strong>r<br />
(new InputStreamRea<strong>de</strong>r(client.getInputStream()));
Steps for Implementing a Client<br />
(Continued)<br />
4. Do I/O with the input and output Streams<br />
– For the output stream, PrintWriter, use print, println, and printf, similar to<br />
System.out.print/println/printf<br />
• The main difference is that you can create PrintWriters for different<br />
Unico<strong>de</strong> characters sets, and you can’t with PrintStream (the class<br />
of System.out).<br />
– For input stream, BufferedRea<strong>de</strong>r, call read to get a single char or an<br />
array of characters, or call readLine to get a whole line<br />
• Note that readLine returns null if the connection was terminated (i.e.<br />
on EOF), but waits otherwise<br />
– You can use ObjectInputStream and ObjectOutputStream for<br />
Java-to-Java communication. Very powerful and simple.<br />
5. Close the socket when done<br />
client.close();<br />
• Also closes the associated input and output streams<br />
546<br />
jeudi 26 janvier 12
Exceptions<br />
• UnknownHostException<br />
–If host passed to Socket constructor is not known to DNS<br />
server.<br />
• Note that you may use an IP address string for the host<br />
• IOException<br />
547<br />
jeudi 26 janvier 12<br />
–Timeout<br />
–Connection refused by server<br />
–Interruption or other unexpected problem<br />
• Server closing connection does not cause an error when reading:<br />
null is returned from readLine
Helper Class: SocketUtils<br />
• I<strong>de</strong>a<br />
–It is common to make BufferedRea<strong>de</strong>r and PrintWriter from a<br />
Socket, so simplify the syntax slightly<br />
• Co<strong>de</strong><br />
public class SocketUtils {<br />
}<br />
548<br />
jeudi 26 janvier 12<br />
public static BufferedRea<strong>de</strong>r getRea<strong>de</strong>r(Socket s) throws IOException {<br />
return(new BufferedRea<strong>de</strong>r<br />
(new InputStreamRea<strong>de</strong>r(s.getInputStream())));<br />
}<br />
public static PrintWriter getWriter(Socket s) throws IOException {<br />
// Second argument of true means autoflush.<br />
return (new PrintWriter(s.getOutputStream(), true));<br />
}
Requesting Internet Permission<br />
• Apps that use internet must say so<br />
–User will be notified that app wants internet permission, and<br />
can <strong>de</strong>ny it. Apps that do not request permission will be<br />
<strong>de</strong>nied access by the Android OS<br />
• It is possible with effort to circumvent this by launching a hid<strong>de</strong>n<br />
Web browser that has data embed<strong>de</strong>d in URL<br />
– See http://dtors.org/2010/08/06/circumventing-android-permissions/<br />
• AndroidManifest.xml<br />
<br />
<br />
<br />
<br />
…<br />
<br />
549<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Example:<br />
NIST Time Server<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Time from US National Inst. of<br />
Standards & Technology (NIST)<br />
• I<strong>de</strong>a<br />
–NIST sponsors several servers with high-precision time<br />
• The simplest to read is Daytime Protocol (RFC-867), which<br />
returns the time on the second line of the response to a<br />
connection. Runs on port 13.<br />
– See http://www.nist.gov/pml/div688/grp40/its.cfm<br />
– One popular host name is time-b.nist.gov<br />
• Approach<br />
551<br />
jeudi 26 janvier 12<br />
–Make a Socket connection to time-b.nist.gov on port 13<br />
–Create a BufferedRea<strong>de</strong>r (no PrintWriter nee<strong>de</strong>d)<br />
–Read first line of result and ignore it<br />
–Read second line of result and print it out
Manifest File<br />
(AndroidManifest.xml)<br />
<br />
<br />
<br />
...<br />
<br />
552<br />
jeudi 26 janvier 12
Layout File<br />
(res/layout/nist_time.xml)<br />
<br />
<br />
<br />
<br />
<br />
553<br />
jeudi 26 janvier 12
Values Files<br />
• res/values/strings.xml<br />
–Defines title, prompts, and button labels for all Activities in<br />
this section.<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/colors.xml<br />
–Defines foreground color for some of the results<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/dimens.xml<br />
–Gives font sizes.<br />
• Used in portrait mo<strong>de</strong>.<br />
• res/values-land/dimens.xml<br />
554<br />
jeudi 26 janvier 12<br />
–Gives font sizes.<br />
• Used in landscape mo<strong>de</strong>.
Main Activity<br />
(NistTimeActivity.java)<br />
public class NistTimeActivity extends Activity {<br />
private String mHost = "time-b.nist.gov";<br />
private int mPort = 13;<br />
private TextView mResultDisplay;<br />
555<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.nist_time);<br />
mResultDisplay =<br />
(TextView)findViewById(R.id.time_display);<br />
}
}<br />
Main Activity, Continued<br />
(NistTimeActivity.java)<br />
556<br />
jeudi 26 janvier 12<br />
public void showTime(View clickedButton) {<br />
try {<br />
Socket socket = new Socket(mHost, mPort);<br />
BufferedRea<strong>de</strong>r in = SocketUtils.getRea<strong>de</strong>r(socket);<br />
in.readLine(); // Ignore leading blank line<br />
String timeResult = in.readLine();<br />
mResultDisplay.setText(timeResult);<br />
socket.close();<br />
} catch (UnknownHostException uhe) {<br />
mResultDisplay.setText("Unknown host: " + mHost);<br />
uhe.printStackTrace(); // View this in DDMS window<br />
} catch (IOException ioe) {<br />
mResultDisplay.setText("IOException: " + ioe);<br />
ioe.printStackTrace(); // View this in DDMS window<br />
}<br />
}
Results<br />
557<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Asi<strong>de</strong>:<br />
String Formatting and<br />
Parsing<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Formatting and Parsing<br />
Strategies<br />
• I<strong>de</strong>a<br />
–Simple to connect to a server and create Rea<strong>de</strong>r/Writer<br />
–So, hard parts are formatting request and parsing response<br />
• Approach<br />
559<br />
jeudi 26 janvier 12<br />
–Formatting requests<br />
• Use printf (aka String.format)<br />
–Parsing response: simplest<br />
• Use StringTokenizer<br />
–Parsing response: more powerful<br />
• Use String.split with regular expressions<br />
–Parsing response: most powerful<br />
• Use Pattern and full regex library<br />
– Not covered in this tutorial
Formatted Output: printf<br />
• Takes a variable number of arguments<br />
–System.out.printf("Formatting String", arg1, arg2, …);<br />
• Advantages<br />
–Lets you insert values into output without much clumsier<br />
String concatenation.<br />
–Lets you control the width of results so things line up<br />
–Lets you control the number of digits after the <strong>de</strong>cimal point<br />
in numbers, for consistent-looking output<br />
• Very similar to C/C++ printf function<br />
560<br />
jeudi 26 janvier 12<br />
–If you know printf in C/C++, you can probably use Java's<br />
printf immediately without reading any documentation<br />
• Although some additions in time formatting and locales<br />
–Use String.format to get the equivalent of C’s sprintf
Simple Example: printf vs. println<br />
• General i<strong>de</strong>a<br />
– Each %s entry in formatting string is replaced by next argument in<br />
argument list. %n means newline.<br />
• Example<br />
public static void printSomeStrings() {<br />
String firstName = "John";<br />
String lastName = "Doe";<br />
int numPets = 7;<br />
String petType = "chickens";<br />
System.out.printf("%s %s has %s %s.%n",<br />
firstName, lastName, numPets, petType);<br />
System.out.println(firstName + " " + lastName +<br />
" has " + numPets + " " +<br />
petType + ".");<br />
}<br />
• Result:<br />
John Doe has 7 chickens.<br />
John Doe has 7 chickens.<br />
561<br />
jeudi 26 janvier 12
Controlling Formatting<br />
• Different flags<br />
–%s for strings, %f for floats/doubles, %t for dates, etc.<br />
• Unlike in C/C++, you can use %s for any type (even nums)<br />
• Various extra entries can be inserted<br />
–To control width, number of digits, commas, justification,<br />
type of date format, and more<br />
• Complete <strong>de</strong>tails<br />
–printf uses mini-language<br />
• Complete coverage would take an entire lecture<br />
• However, basic usage is straightforward<br />
–For complete coverage, see<br />
http://download.oracle.com/javase/6/docs/api/java/util/Formatter.html#syntax<br />
• Most common errors<br />
– Using + instead of , between arguments (printf uses varargs)<br />
– Forgetting to add %n at the end if you want a newline (not automatic)<br />
562<br />
jeudi 26 janvier 12
Printf Formatting Options<br />
%s<br />
%d<br />
Stands For Options Example<br />
String. Can output any data<br />
type. If arg is Object, toString is<br />
called.<br />
Decimal. Outputs whole<br />
number in base 10. Also %x<br />
and %o for hex and octal.<br />
%f Floating point. Lets you line<br />
up <strong>de</strong>cimal point and control<br />
precision.<br />
%tx<br />
563<br />
jeudi 26 janvier 12<br />
Time (or date). %tA for day,<br />
%tB for month, %tY for year,<br />
and many more.<br />
%widths<br />
Gives min num of chars.<br />
Spaces ad<strong>de</strong>d to left if<br />
nee<strong>de</strong>d.<br />
%widthd %,widthd<br />
Gives min width; inserts<br />
commas.<br />
%width.precisionf<br />
%,width.precisionf<br />
width inclu<strong>de</strong>s comma and<br />
<strong>de</strong>cimal point.<br />
Date now = new Date();<br />
printf("%8s", "Hi")<br />
outputs<br />
" Hi"<br />
printf("%tA, %tB ,%tY", now, now, now)<br />
outputs<br />
"Thursday, November 17, 2005"<br />
printf("%,9d", 1234)<br />
outputs<br />
" 1,234"<br />
printf("%6.2f", Math.PI)<br />
outputs<br />
" 3.14"<br />
%n Outputs OS-specific end of line (linefeed on Linux/Unix, CR/LF pair on Windows)
Printf Example: Controlling Width<br />
and Precision<br />
public class CEO {<br />
private String name;<br />
private double salary; // In billions<br />
}<br />
564<br />
jeudi 26 janvier 12<br />
public CEO(String name, double salary) {<br />
this.name = name;<br />
this.salary = salary;<br />
}<br />
public String getName() { return(name); }<br />
public double getSalary() { return(salary); }<br />
Note that you cannot make a class with a “main” method in an Android app and run it from Eclipse in the<br />
usual way (R-click, Run As � Java Application). So, the printf and parsing examples are in a separate<br />
project called NetworkingSupport. This project also contains the servlet used in the second networking<br />
lecture.
Printf Example: Controlling Width<br />
and Precision<br />
public static void printSomeSalaries() {<br />
CEO[] softwareCEOs =<br />
{ new CEO("Steve Jobs", 3.1234),<br />
new CEO("Scott McNealy", 45.5678),<br />
new CEO("Jeff Bezos", 567.982323),<br />
new CEO("Larry Ellison", 6789.0),<br />
new CEO("Bill Gates", 78901234567890.12)};<br />
System.out.println("SALARIES:");<br />
for(CEO ceo: softwareCEOs) {<br />
System.out.printf("%15s: $%,8.2f%n",<br />
ceo.getName(), ceo.getSalary());<br />
}}<br />
SALARIES:<br />
Steve Jobs: $ 3.12<br />
Scott McNealy: $ 45.57<br />
Jeff Bezos: $ 567.98<br />
Larry Ellison: $6,789.00<br />
Bill Gates: $78,901,234,567,890.12<br />
565<br />
jeudi 26 janvier 12
Parsing Strings Using<br />
StringTokenizer<br />
• I<strong>de</strong>a<br />
566<br />
jeudi 26 janvier 12<br />
–Build a tokenizer from an initial string<br />
–Retrieve tokens one at a time with nextToken<br />
–You can also see how many tokens are remaining<br />
(countTokens) or simply test if the number of tokens<br />
remaining is nonzero (hasMoreTokens)<br />
StringTokenizer tok<br />
= new StringTokenizer(input, <strong>de</strong>limiters);<br />
while (tok.hasMoreTokens()) {<br />
doSomethingWith(tok.nextToken());<br />
}
StringTokenizer<br />
• Constructors<br />
– StringTokenizer(String input, String <strong>de</strong>limiters)<br />
– StringTokenizer(String input, String <strong>de</strong>limiters,<br />
boolean inclu<strong>de</strong>Delimiters)<br />
– StringTokenizer(String input)<br />
• Default <strong>de</strong>limiter set is " \t\n\r\f" (whitespace)<br />
• Methods<br />
– nextToken(), nextToken(String <strong>de</strong>limiters)<br />
– countTokens()<br />
– hasMoreTokens()<br />
• Also see methods in String class<br />
– split, substring, in<strong>de</strong>xOf, startsWith, endsWith, compareTo, …<br />
– Java has good support for regular expressions<br />
567<br />
jeudi 26 janvier 12
Interactive Tokenizer: Example<br />
import java.util.StringTokenizer;<br />
public class TokTest {<br />
public static void main(String[] args) {<br />
if (args.length == 2) {<br />
String input = args[0], <strong>de</strong>limiters = args[1];<br />
StringTokenizer tok<br />
= new StringTokenizer(input, <strong>de</strong>limiters);<br />
while (tok.hasMoreTokens()) {<br />
System.out.println(tok.nextToken());<br />
}<br />
} else {<br />
System.out.println<br />
("Usage: java TokTest string <strong>de</strong>limiters");<br />
}<br />
}<br />
}<br />
568<br />
jeudi 26 janvier 12
Interactive Tokenizer: Result<br />
> java TokTest http://www.microsoft.com/~gates/ :/.<br />
http<br />
www<br />
microsoft<br />
com<br />
~gates<br />
> java TokTest "if (tok.hasMoreTokens()) {" "(){. "<br />
if<br />
tok<br />
hasMoreTokens<br />
569<br />
jeudi 26 janvier 12
Parsing Strings using the split<br />
method of String<br />
• Basic usage<br />
– String[] tokens = mainString.split(<strong>de</strong>limiterString);<br />
• Differences from StringTokenizer<br />
– Entire string is the <strong>de</strong>limiter (not one-char <strong>de</strong>limiters)<br />
• "foobar".split("ob") returns "fo" and "ar"<br />
• "foobar".split("bo") returns "foobar"<br />
– You can use regular expressions in the <strong>de</strong>limiter<br />
• ^, $, *, +, ., etc for beginning of String, end of String, 0 or more, 1 or more,<br />
any one character, etc.<br />
• See http://download.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html#sum<br />
– Unless you use "+", an empty string is returned between <strong>de</strong>limiters<br />
• "foobar".split("o") returns "f", "", and "bar"<br />
• "foobar".split("o+") returns "f" and "bar"<br />
– You can supply second argument to split<br />
• Giving max splits; any extras go in final string<br />
570<br />
jeudi 26 janvier 12
Importance of Regular<br />
Expressions<br />
• I<strong>de</strong>a<br />
–String.split and other<br />
methods use regular<br />
expressions<br />
–So do many other languages.<br />
Knowing regex syntax is<br />
an important part of every<br />
programmer’s repertoire.<br />
• Tutorials<br />
571<br />
jeudi 26 janvier 12<br />
From Randall Munroe and xkcd.com<br />
– http://download.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html#sum<br />
– http://download.oracle.com/javase/tutorial/essential/regex/
Interactive Tokenizer: Example<br />
public class SplitTest {<br />
public static void main(String[] args) {<br />
if (args.length == 2) {<br />
String[] tokens = args[0].split(args[1]);<br />
for(String token: tokens) {<br />
if (token.length() != 0) {<br />
System.out.println(token);<br />
}<br />
}<br />
} else {<br />
System.out.println<br />
("Usage: java SplitTest string <strong>de</strong>limeters");<br />
}<br />
}<br />
}<br />
572<br />
jeudi 26 janvier 12
Interactive Tokenizer: Result<br />
> java TokTest http://www.microsoft.com/~gates/ :/.<br />
http<br />
www<br />
microsoft<br />
com<br />
~gates<br />
> java SplitTest http://www.microsoft.com/~gates/ :/.<br />
http<br />
www.microsoft.com/~gates/<br />
> java SplitTest http://www.microsoft.com/~gates/ [:/.]+<br />
http<br />
www<br />
microsoft<br />
com<br />
~gates<br />
573<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example:<br />
FTP Welcome Messages<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
FTP Server Welcome Messages<br />
• I<strong>de</strong>a<br />
–When you connect to an FTP server, you usually get a<br />
welcome message. The problem is that it can be a variable<br />
number of lines long.<br />
• If multiline, first line should start with "220-" (220 dash) and last<br />
line should start with "220 " (220 space)<br />
• Approach<br />
575<br />
jeudi 26 janvier 12<br />
–Connect to server on port 21 and read first line<br />
• If it does not start with "220-", print it and exit<br />
–If first line does start with "220-", read and echo lines until<br />
you find one that starts with "220 ".
Example Welcome Messages<br />
• ftp.microsoft.com<br />
> ftp ftp.microsoft.com<br />
220 Microsoft FTP Service<br />
• ftp.oracle.com<br />
> ftp ftp.oracle.com<br />
220-***********************************************************************<br />
220-Oracle FTP Server<br />
220-<br />
220-The use of this FTP server is governed by United States Export Admini-<br />
220-stration Regulations. Details of the U.S. Commercial Encryption Export<br />
220-Controls can be found at the Bureau of Industry and Security web site.<br />
220-All Oracle products are subject to U.S. Export Laws. Diversion contrary<br />
220-to U.S. law is prohibited.<br />
...<br />
220-<br />
220-****************************************************************************<br />
220-<br />
220<br />
576<br />
jeudi 26 janvier 12
Example Welcome Message<br />
> ftp ftp.ngc.com<br />
220-***************************************************************************<br />
* Access Restricted *<br />
* The Northrop Grumman computer network is for use, only by authorized *<br />
* users, and only for authorized purposes. Unauthorized sending, *<br />
* transmitting, or otherwise disseminating proprietary data or tra<strong>de</strong> *<br />
* secrets, private company information or classified data is strictly *<br />
* prohibited. The network and its contents are the exclusive property of *<br />
* the company. There is no right of privacy on the part of any<br />
*<br />
* individual, regarding any information transmitted, stored or received<br />
*<br />
* via the network. Employees may access the Northrop Grumman Global *<br />
* Network only by using tools provi<strong>de</strong>d by IT Solutions. Use of other *<br />
* remote access services is strictly prohibited. Use or access to the<br />
*<br />
* network constitutes consent to the company's acceptable use provisions *<br />
* contained in Corporate Procedure R1, and to the monitoring, storage, *<br />
* retrieval or disclosure or any information transmitted, stored or *<br />
* received via the network for any purpose, including employee *<br />
* discipline, contractual remedies or criminal prosecutions. *<br />
* Passwords must comply with Corporate policy UO J104. *<br />
***************************************************************************<br />
220 FTP server ready<br />
577<br />
jeudi 26 janvier 12
Manifest File<br />
(AndroidManifest.xml)<br />
<br />
<br />
<br />
...<br />
<br />
578<br />
jeudi 26 janvier 12
Layout File: Portrait Mo<strong>de</strong><br />
(res/layout/ftp_message.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
579<br />
jeudi 26 janvier 12
Layout File: Landscape Mo<strong>de</strong><br />
(res/layout-land/ftp_message.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
580<br />
jeudi 26 janvier 12
Values Files<br />
• res/values/strings.xml<br />
–Defines title, prompts, and button labels for all Activities in<br />
this section.<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/colors.xml<br />
–Defines foreground color for some of the results<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/dimens.xml<br />
–Gives font sizes.<br />
• Used in portrait mo<strong>de</strong>.<br />
• res/values-land/dimens.xml<br />
581<br />
jeudi 26 janvier 12<br />
–Gives font sizes.<br />
• Used in landscape mo<strong>de</strong>.
Main Activity<br />
(FtpMessageActivity.java)<br />
public class FtpMessageActivity extends Activity {<br />
private EditText mFtpHost;<br />
private TextView mFtpMessageResult;<br />
private static final int FTP_PORT = 21;<br />
582<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.ftp_message);<br />
mFtpHost = (EditText)findViewById(R.id.ftp_host);<br />
mFtpMessageResult =<br />
(TextView)findViewById(R.id.ftp_message_result);<br />
}
Main Activity, Continued<br />
(FtpMessageActivity.java)<br />
583<br />
jeudi 26 janvier 12<br />
public void showMessage(View clickedButton) {<br />
String host = mFtpHost.getText().toString();<br />
try {<br />
Socket socket = new Socket(host, FTP_PORT);<br />
BufferedRea<strong>de</strong>r in = SocketUtils.getRea<strong>de</strong>r(socket);<br />
List results = new ArrayList();<br />
String line = in.readLine();<br />
results.add(line);<br />
if (line.startsWith("220-")) {<br />
while((line = in.readLine()) != null) {<br />
results.add(line);<br />
if ((line.equals("220") ||<br />
line.startsWith("220 "))) {<br />
break;<br />
}<br />
}<br />
}<br />
String output = makeOutputString(results);<br />
mFtpMessageResult.setText(output);<br />
socket.close();
}<br />
Main Activity, Continued<br />
(FtpMessageActivity.java)<br />
584<br />
jeudi 26 janvier 12<br />
}<br />
} catch (UnknownHostException uhe) {<br />
mFtpMessageResult.setText("Unknown host: " + host);<br />
uhe.printStackTrace(); // View this in DDMS window<br />
} catch (IOException ioe) {<br />
mFtpMessageResult.setText("IOException: " + ioe);<br />
ioe.printStackTrace(); // View this in DDMS window<br />
}<br />
private String makeOutputString(List results) {<br />
StringBuil<strong>de</strong>r output = new StringBuil<strong>de</strong>r();<br />
for (String s: results) {<br />
output.append(s + "\n");<br />
}<br />
return(output.toString());<br />
}
Results<br />
585<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example: Verifying URLs<br />
with the HEAD Command<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
The HEAD Command<br />
• I<strong>de</strong>a<br />
– Web browsers normally send GET or POST requests<br />
• Server responds with status line, response hea<strong>de</strong>rs, blank line, and<br />
then the document<br />
– If you only care about status line, send HEAD instead<br />
• Server responds only with status line and response hea<strong>de</strong>rs<br />
• Approach<br />
– Parse a URL into the host, port (80 if none) and URI<br />
– Connect to host on port. Send request for URI plus Host request<br />
hea<strong>de</strong>r (for servers with virtual hosting)<br />
– Read status line and see if it is 2xx (good), 3xx (forwar<strong>de</strong>d) or<br />
anything else (bad).<br />
• If forwar<strong>de</strong>d, keep reading to find Location hea<strong>de</strong>r<br />
• Note<br />
– Here we use no HTTP-specific classes. Next tutorial section<br />
covers HttpURLConnection and other HTTP-specific classes.<br />
587<br />
jeudi 26 janvier 12
HTTP Request/Response:<br />
GET<br />
• Request<br />
GET /foo/bar.html HTTP/1.1<br />
Host: ...<br />
Hea<strong>de</strong>r2: ...<br />
...<br />
Hea<strong>de</strong>rN:<br />
(Blank Line)<br />
588<br />
jeudi 26 janvier 12<br />
• Response<br />
HTTP/1.1 200 OK<br />
Content-Type: text/html<br />
Hea<strong>de</strong>r2: ...<br />
...<br />
Hea<strong>de</strong>rN: ...<br />
(Blank Line)<br />
<br />
<br />
...<br />
<br />
...<br />
HTTP Request/Response:<br />
HEAD<br />
• Request<br />
HEAD /foo/bar.html HTTP/1.1<br />
Host: ...<br />
Hea<strong>de</strong>r2: ...<br />
...<br />
Hea<strong>de</strong>rN:<br />
(Blank Line)<br />
589<br />
jeudi 26 janvier 12<br />
• Response<br />
HTTP/1.1 200 OK<br />
Content-Type: text/html<br />
Hea<strong>de</strong>r2: ...<br />
...<br />
Hea<strong>de</strong>rN: ...
Using Telnet to Test Server<br />
Commands<br />
• Telnet<br />
–Most people think of telnet as a tool for logging into a remote<br />
server on <strong>de</strong>fault login port (23)<br />
–But, it is really more general: a tool for connecting to a<br />
remote server on any port and interactively sending<br />
commands and looking at results<br />
• Enabling telnet on Windows 7 or Vista<br />
590<br />
jeudi 26 janvier 12<br />
–Starting with Windows Vista, telnet is disabled by <strong>de</strong>fault<br />
• To enable it, see http://technet.microsoft.com/<br />
en-us/library/cc771275(WS.10).aspx<br />
• Or Google for “install telnet windows 7” and above page will<br />
come up #1<br />
• You may also need to turn on local echo – Unix telnet clients are<br />
much more convenient
Example: Steve Ballmer’s Home<br />
Page at Microsoft<br />
> telnet www.microsoft.com 80<br />
Trying 207.46.19.254...<br />
Connected to lb1.www.ms.akadns.net.<br />
Escape character is '^]'.<br />
HEAD /presspass/exec/steve/<strong>de</strong>fault.aspx HTTP/1.0<br />
HTTP/1.1 200 OK<br />
Cache-Control: private<br />
Content-Length: 182105<br />
Content-Type: text/html; charset=utf-8<br />
Server: Microsoft-IIS/7.5<br />
X-AspNet-Version: 2.0.50727<br />
VTag: 279105531500000000<br />
P3P: CP="..."<br />
X-Powered-By: ASP.NET<br />
Date: Tue, 02 Aug 2011 17:58:43 GMT<br />
Connection: keep-alive<br />
Connection to lb1.www.ms.akadns.net<br />
closed by foreign host.<br />
591<br />
jeudi 26 janvier 12<br />
This URI corresponds to the full URL http://www.microsoft.com/<br />
presspass/exec/steve/<strong>de</strong>fault.aspx, which is the real bio page for<br />
Steve Ballmer.<br />
Also, since microsoft.com is using <strong>de</strong>dicated hosting, I can use the<br />
simpler HTTP 1.0 HEAD request (with no Host hea<strong>de</strong>r). The Java<br />
co<strong>de</strong> will use HTTP 1.1 with the Host hea<strong>de</strong>r, so that it can also<br />
handler sites that use virtual (shared) hosting.
Example: Larry Ellison’s Home<br />
Page at Microsoft<br />
> telnet www.microsoft.com 80<br />
Trying 207.46.19.254...<br />
Connected to lb1.www.ms.akadns.net.<br />
Escape character is '^]'.<br />
HEAD /presspass/exec/larry/<strong>de</strong>fault.aspx HTTP/1.0<br />
HTTP/1.1 302 Found<br />
Content-Length: 293<br />
Content-Type: text/html; charset=utf-8<br />
Location: http://www.microsoft.com/library/errorpages/<br />
smarterror.aspx?aspxerrorpath=http%3a%2f<br />
%2f207.46.21.164%2fpresspass%2fexec%2flarry%2f<strong>de</strong>fault.aspx<br />
...<br />
Date: Tue, 02 Aug 2011 18:06:11 GMT<br />
Connection: keep-alive<br />
Connection to lb1.www.ms.akadns.net closed by foreign host.<br />
592<br />
jeudi 26 janvier 12<br />
This corresponds to http://www.microsoft.com/presspass/exec/larry/<br />
<strong>de</strong>fault.aspx, which is a nonexistent page. The page they forward to<br />
should return 404 to prevent in<strong>de</strong>xing by search engines.
Manifest File<br />
(AndroidManifest.xml)<br />
<br />
<br />
<br />
...<br />
<br />
593<br />
jeudi 26 janvier 12
Layout File: Portrait Mo<strong>de</strong><br />
(res/layout/url_checker.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
594<br />
jeudi 26 janvier 12
Layout File: Landscape Mo<strong>de</strong><br />
(res/layout-land/url_checker.xml)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
595<br />
jeudi 26 janvier 12
Values Files<br />
• res/values/strings.xml<br />
–Defines title, prompts, and button labels for all Activities in<br />
this section.<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/colors.xml<br />
–Defines foreground color for some of the results<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/dimens.xml<br />
–Gives font sizes.<br />
• Used in portrait mo<strong>de</strong>.<br />
• res/values-land/dimens.xml<br />
596<br />
jeudi 26 janvier 12<br />
–Gives font sizes.<br />
• Used in landscape mo<strong>de</strong>.
Main Activity<br />
(UrlCheckerActivity.java)<br />
public class UrlCheckerActivity extends Activity {<br />
private EditText mUrlToTest;<br />
private TextView mUrlMessageResult;<br />
597<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.url_checker);<br />
mUrlToTest =<br />
(EditText)findViewById(R.id.url_to_test);<br />
mUrlMessageResult =<br />
(TextView)findViewById<br />
(R.id.url_validation_result);<br />
}
Main Activity, Continued<br />
(UrlCheckerActivity.java)<br />
598<br />
jeudi 26 janvier 12<br />
public void checkUrl(View clickedButton) {<br />
String url = mUrlToTest.getText().toString();<br />
UrlParser parser = new UrlParser(url);<br />
String host = parser.getHost();<br />
int port = parser.getPort();<br />
String uri = parser.getUri();<br />
try {<br />
Socket socket = new Socket(host, port);<br />
PrintWriter out = SocketUtils.getWriter(socket);<br />
BufferedRea<strong>de</strong>r in = SocketUtils.getRea<strong>de</strong>r(socket);<br />
out.printf("HEAD %s HTTP/1.1\r\n", uri);<br />
out.printf("Host: %s\r\n", host);<br />
out.printf("Connection: close\r\n\r\n");<br />
String serverResult = in.readLine();<br />
String info = statusInfo(serverResult, in);<br />
mUrlMessageResult.setText(info);<br />
socket.close();
Main Activity, Continued<br />
(UrlCheckerActivity.java)<br />
599<br />
jeudi 26 janvier 12<br />
}<br />
} catch (UnknownHostException uhe) {<br />
mUrlMessageResult.setText("Unknown host: " + host);<br />
uhe.printStackTrace(); // View this in DDMS window<br />
} catch (IOException ioe) {<br />
mUrlMessageResult.setText("IOException: " + ioe);<br />
ioe.printStackTrace(); // View this in DDMS window<br />
}
Main Activity, Continued<br />
(UrlCheckerActivity.java)<br />
600<br />
jeudi 26 janvier 12<br />
private String statusInfo(String serverResult, BufferedRea<strong>de</strong>r in)<br />
throws IOException {<br />
StatusLineParser statusLine = new StatusLineParser(serverResult);<br />
String result;<br />
if (statusLine.isGood()) {<br />
result = String.format("Good URL: %s -- %s",<br />
statusLine.getStatusCo<strong>de</strong>(),<br />
statusLine.getMessage());<br />
} else if (statusLine.isForwar<strong>de</strong>d()) {<br />
result = String.format("URL forwar<strong>de</strong>d to %s",<br />
location(in));<br />
} else {<br />
result = String.format("Bad URL: %s -- %s",<br />
statusLine.getStatusCo<strong>de</strong>(),<br />
statusLine.getMessage());<br />
}<br />
return(result);<br />
}
Main Activity, Continued<br />
(UrlCheckerActivity.java)<br />
601<br />
jeudi 26 janvier 12<br />
private String location(BufferedRea<strong>de</strong>r in) throws IOException {<br />
String line;<br />
while((line = in.readLine()) != null) {<br />
if (line.toUpperCase().startsWith("LOCATION")) {<br />
String[] results = line.split("\\s+", 2);<br />
return(results[1]);<br />
}<br />
}<br />
return("(Unknown Location)");<br />
}
Helper Classes<br />
• StatusLineParser<br />
–Reads status line and breaks it into three parts: HTTP version,<br />
status co<strong>de</strong>, and message<br />
• Also isGood (status co<strong>de</strong> in the 200’s), isForwar<strong>de</strong>d (301/302)<br />
and isBad (anything else) methods<br />
• UrlParser<br />
602<br />
jeudi 26 janvier 12<br />
–Breaks a URL like http://host:port/path into the host, port, and<br />
path parts. Uses 80 if no port specified.<br />
–Note that the builtin URL class already does this. See next<br />
lecture. But Android has no builtin support for protocols other<br />
than HTTP, so learning to do it yourself is important.
Results<br />
603<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
More Reading<br />
• JavaDoc<br />
– Socket<br />
• http://<strong>de</strong>veloper.android.com/reference/java/net/Socket.html<br />
– Pattern (gives regular expression <strong>de</strong>tails)<br />
• http://<strong>de</strong>veloper.android.com/reference/java/util/regex/Pattern.html<br />
• Tutorial: Networking<br />
– http://download.oracle.com/javase/tutorial/networking/<br />
• Not Android specific, but still very good networking coverage<br />
• Chapters<br />
– Networking and Web Services<br />
• From Android in Action by Ableson et al<br />
– Communicating via the Internet<br />
• From The Busy Co<strong>de</strong>r’s Gui<strong>de</strong> to Android Development<br />
by Mark Murphy (http://commonsware.com/Android/)<br />
605<br />
jeudi 26 janvier 12
Summary<br />
• Basics<br />
– Socket socket = new Socket(host, port);<br />
– PrintWriter out = SocketUtils.getWriter(socket);<br />
– BufferedRea<strong>de</strong>r in = SocketUtils.getRea<strong>de</strong>r(socket);<br />
• Slightly longer if you don’t use SocketUtils<br />
• Catch UnknownHostException and IOException<br />
– Ask for Internet permission in AndroidManifest.xml<br />
• Formatting and parsing<br />
– Format request: printf<br />
– Handle response<br />
• Read lines with readLine. Remember it blocks and waits for either<br />
end-of-line (String) or closed connection (null).<br />
• Parse the line with StringTokenizer or String.split<br />
606<br />
jeudi 26 janvier 12<br />
– To use the split method, learn regular expressions
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Network Programming:<br />
Part II (HTTP-Specific Techniques)<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Part I (previous section): general networking<br />
– Socket basics<br />
– Requesting Internet permission<br />
– Example: NIST atomic time<br />
– Asi<strong>de</strong>: simple String formatting and parsing<br />
– Example: FTP welcome messages<br />
– Example: validating URLs with HEAD<br />
• Part II (this section): HTTP-specific approaches<br />
– HttpURLConnection<br />
– HttpClient<br />
– Examples: Searching Web pages<br />
– Using JSON<br />
– Example: remote loan calculations<br />
– Example: Google translation services<br />
608<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Big I<strong>de</strong>a<br />
• Many ways to communicate with a server<br />
610<br />
jeudi 26 janvier 12<br />
–Socket class<br />
• Lets you do general-purpose network programming<br />
– Same as with <strong>de</strong>sktop Java programming<br />
–HttpURLConnection<br />
• Simplifies connections to HTTP servers<br />
– Same as with <strong>de</strong>sktop Java programming<br />
–HttpClient<br />
• Simplest way to download entire content of a URL<br />
– Not standard in Java SE, but standard in Android<br />
–JSONObject<br />
• Simplifies creation and parsing of JSON data<br />
– Not standard in Java SE, but standard in Android
jeudi 26 janvier 12<br />
HttpURLConnection<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
URL and HttpURLConnection:<br />
Overview<br />
• URL<br />
– The URL class can parse a URL and extract its components<br />
(protocol, host, port, URI, etc.)<br />
– You can use openConnection to get a stream to the URL<br />
• HttpURLConnection<br />
– If the URL’s protocol is HTTP, cast the result of openConnection<br />
to HttpURLConnection<br />
• Lets you read the status co<strong>de</strong><br />
612<br />
jeudi 26 janvier 12<br />
– 200, 301, 404, etc.<br />
• Lets you set request hea<strong>de</strong>rs<br />
– Accept, Referer, User-Agent, etc.<br />
• Lets you read response hea<strong>de</strong>rs<br />
– Content-Type, Location, etc.<br />
• Special case for cookies<br />
– Use CookieManager instead of raw hea<strong>de</strong>rs
URL: Details<br />
• openConnection<br />
–Establishes connection to server.<br />
• Cast result to HttpURLConnection for more control<br />
• Uses GET by <strong>de</strong>fault. To use POST, call setDoOutput(true) and<br />
send data via openOutputStream<br />
• openInputStream<br />
–Gets a Stream for reading data. Wrap in InputStreamRea<strong>de</strong>r<br />
(usually buffered) to use readLine.<br />
• getProtocol, getHost, getPort, getFile, getRef<br />
613<br />
jeudi 26 janvier 12<br />
–Returns the different components of the URL.<br />
• The port is -1 if none specified, so you can distinguish an omitted<br />
port from an explicit 80.
Simple URL Methods: Example<br />
import java.net.*;<br />
public class UrlTest {<br />
public static void main(String[] args) {<br />
if (args.length == 1) {<br />
try {<br />
URL url = new URL(args[0]);<br />
System.out.println<br />
("URL: " + url.toExternalForm() + "\n" +<br />
" File: " + url.getFile() + "\n" +<br />
" Host: " + url.getHost() + "\n" +<br />
" Port: " + url.getPort() + "\n" +<br />
" Protocol: " + url.getProtocol() + "\n" +<br />
" Reference: " + url.getRef());<br />
} catch(MalformedURLException mue) {<br />
System.out.println("Bad URL.");<br />
}<br />
} else<br />
System.out.println("Usage: UrlTest ");<br />
}<br />
}<br />
614<br />
jeudi 26 janvier 12
Simple URL Methods: Results<br />
> java UrlTest http://www.irs.gov/mission/#squeezing-them-dry<br />
URL: http://www.irs.gov/mission/#squeezing-them-dry<br />
File: /mission/<br />
Host: www.irs.gov<br />
Port: -1<br />
Protocol: http<br />
Reference: squeezing-them-dry<br />
615<br />
jeudi 26 janvier 12<br />
What month do you think it was when I first wrote this example?
HttpURLConnection: Details<br />
• Getting a connection from a URL<br />
URL url = new URL("http://…");<br />
HttpURLConnection urlConnection =<br />
(HttpURLConnection)url.openConnection();<br />
• Reading data<br />
BufferedRea<strong>de</strong>r in =<br />
new BufferedRea<strong>de</strong>r(new InputStreamRea<strong>de</strong>r<br />
(urlConnection.getInputStream()));<br />
while ((line = in.readLine()) != null) {<br />
doSomethingWith(line);<br />
}<br />
• Other methods<br />
616<br />
jeudi 26 janvier 12<br />
–disconnect, getResponseCo<strong>de</strong>, getHea<strong>de</strong>rField<br />
• Call disconnect when done
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example: Searching Web<br />
Pages for Keywords<br />
(Version 1)<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
URL Searcher<br />
• I<strong>de</strong>a<br />
–Print out all lines in a given URL that contain keyword<br />
• Approach<br />
618<br />
jeudi 26 janvier 12<br />
–Read URL and keyword from user<br />
–Call theUrl.openConnection and cast result to<br />
HttpURLConnection<br />
–Attach BufferedRea<strong>de</strong>r to the HttpURLConnection<br />
–Read one line at a time (until null), checking if the line<br />
contains the keyword<br />
–Catch MalformedURLException and IOException<br />
–Call disconnect() when done
Manifest File<br />
(AndroidManifest.xml)<br />
<br />
<br />
<br />
...<br />
<br />
619<br />
jeudi 26 janvier 12
Layout File (res/layout/<br />
url_searcher.xml)<br />
<br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
620<br />
jeudi 26 janvier 12
Values Files<br />
• res/values/strings.xml<br />
–Defines title, prompts, and button labels for all Activities in<br />
this section.<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/colors.xml<br />
–Defines foreground color for some of the results<br />
• Used in both portrait and landscape mo<strong>de</strong>.<br />
• res/values/dimens.xml<br />
–Gives font sizes.<br />
• Used in portrait mo<strong>de</strong>.<br />
• res/values-land/dimens.xml<br />
621<br />
jeudi 26 janvier 12<br />
–Gives font sizes.<br />
• Used in landscape mo<strong>de</strong>.
Main Activity<br />
(UrlSearcher1Activity.java)<br />
public class UrlSearcher1Activity extends Activity {<br />
protected EditText mUrlToSearch, mSearchString;<br />
protected TextView mUrlMessageResult;<br />
protected float mResultTextSize, mErrorTextSize;<br />
622<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.url_searcher);<br />
mUrlToSearch = (EditText)findViewById(R.id.url_to_search);<br />
mSearchString = (EditText)findViewById(R.id.search_string);<br />
mUrlMessageResult =<br />
(TextView)findViewById(R.id.url_search_result);<br />
Resources resources = getResources();<br />
mResultTextSize =<br />
resources.getDimension(R.dimen.url_search_results_size);<br />
mErrorTextSize =<br />
resources.getDimension(R.dimen.url_search_error_size);<br />
}<br />
Note the protected fields and (next sli<strong>de</strong>s) methods – next example will extend this class and share much of the co<strong>de</strong>.
Main Activity, Continued<br />
(UrlSearcher1Activity.java)<br />
623<br />
jeudi 26 janvier 12<br />
public void searchInUrl(View clickedButton) {<br />
String urlString =<br />
mUrlToSearch.getText().toString();<br />
String searchString =<br />
mSearchString.getText().toString();<br />
showResults(urlString, searchString);<br />
}<br />
This is the method called by the Button. Next example will inherit it unchanged.
Main Activity, Continued<br />
(UrlSearcher1Activity.java)<br />
624<br />
jeudi 26 janvier 12<br />
protected void showResults(String urlString, String searchString) {<br />
HttpURLConnection urlConnection = null;<br />
try {<br />
URL url = new URL(urlString);<br />
urlConnection = (HttpURLConnection)url.openConnection();<br />
BufferedRea<strong>de</strong>r in =<br />
new BufferedRea<strong>de</strong>r<br />
(new InputStreamRea<strong>de</strong>r(urlConnection.getInputStream()));<br />
String line;<br />
StringBuil<strong>de</strong>r matches = new StringBuil<strong>de</strong>r("");<br />
int lineNum = 0;<br />
int numMatches = 0;<br />
while ((line = in.readLine()) != null) {<br />
lineNum++;<br />
if(line.contains(searchString)) {<br />
numMatches++;<br />
matches.append(makeMatch(line, lineNum));<br />
}<br />
}<br />
displayResults(matches, numMatches);<br />
This is the method that is overrid<strong>de</strong>n in the next example.
Main Activity, Continued<br />
(UrlSearcher1Activity.java)<br />
625<br />
jeudi 26 janvier 12<br />
}<br />
} catch (MalformedURLException mue) {<br />
showError("Bad URL: " + urlString);<br />
mue.printStackTrace(); // View this in DDMS window<br />
} catch (IOException ioe) {<br />
showError("Error in connection: " + ioe);<br />
ioe.printStackTrace(); // View this in DDMS window<br />
} finally {<br />
if (urlConnection != null) {<br />
urlConnection.disconnect();<br />
}<br />
}<br />
This is a continuation of the showResults method started on previous sli<strong>de</strong>.
Main Activity, Continued<br />
(UrlSearcher1Activity.java)<br />
626<br />
jeudi 26 janvier 12<br />
protected String makeMatch(String text, int lineNum) {<br />
return(String.format("LINE %s: %s%n", lineNum, text));<br />
}<br />
protected void displayResults(StringBuil<strong>de</strong>r matches,<br />
int numMatches) {<br />
if (numMatches > 0) {<br />
showMatches(matches, numMatches);<br />
} else {<br />
showError("No matches");<br />
}<br />
}
}<br />
Main Activity, Continued<br />
(UrlSearcher1Activity.java)<br />
627<br />
jeudi 26 janvier 12<br />
protected void showMatches(StringBuil<strong>de</strong>r matches,<br />
int numMatches) {<br />
String introMessage =<br />
String.format("FOUND %s MATCHES:%n%n",<br />
numMatches);<br />
matches.insert(0, introMessage);<br />
mUrlMessageResult.setTextSize(mResultTextSize);<br />
mUrlMessageResult.setText(matches);<br />
}<br />
protected void showError(String text) {<br />
mUrlMessageResult.setTextSize(mErrorTextSize);<br />
mUrlMessageResult.setText("\n\n" + text);<br />
}
Results<br />
628<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
HttpClient<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
HttpClient<br />
• I<strong>de</strong>a<br />
–A popular class from the Apache HttpComponents suite that is<br />
bundled with Android.<br />
• Minor problem: Android does not document precisely which<br />
version it uses, so hard to use Apache tutorials<br />
• Capabilities<br />
630<br />
jeudi 26 janvier 12<br />
–Simple way to read an entire URL (via GET) into String<br />
–Mo<strong>de</strong>rately simple way to send POST parameters, then read<br />
entire result into a String<br />
–Many, many other capabilities<br />
• But only the simple reading of content is shown in this tutorial.<br />
For other capabilities, see http://hc.apache.org/httpclient-3.x/<br />
tutorial.html
HttpClient: Reading Result of GET<br />
Request<br />
• Make a <strong>de</strong>fault client<br />
–HttpClient client = new DefaultHttpClient();<br />
• Make an HttpGet with address<br />
–HttpGet httpGet = new HttpGet(address);<br />
• Make a String ResponseHandler<br />
–ResponseHandler handler =<br />
new BasicResponseHandler();<br />
• Call client.execute<br />
631<br />
jeudi 26 janvier 12<br />
–String content = client.execute(httpGet, handler);
HttpClient: Reading Result of<br />
POST Request<br />
• Make a <strong>de</strong>fault client<br />
HttpClient client = new DefaultHttpClient();<br />
• Make an HttpPost with address<br />
HttpPost httpPost = new HttpPost(address);<br />
• Make a List of name/value pairs<br />
List params = new ArrayList();<br />
params.add(new BasicNameValuePair(paramName1, paramValue1));<br />
params.add(…); // More names and values. NOT URL-enco<strong>de</strong>d<br />
• Attach POST data<br />
UrlEnco<strong>de</strong>dFormEntity entity = new UrlEnco<strong>de</strong>dFormEntity(params, "UTF-8");<br />
httpPost.setEntity(entity);<br />
• Make a String ResponseHandler<br />
ResponseHandler handler = new BasicResponseHandler();<br />
• Call client.execute<br />
String content = client.execute(httpPost, handler);<br />
632<br />
jeudi 26 janvier 12
HttpUtils<br />
• I<strong>de</strong>a<br />
–A class <strong>de</strong>veloped for this tutorial that wraps up some simple<br />
HttpClient functionality<br />
• Static methods<br />
633<br />
jeudi 26 janvier 12<br />
–urlContent(String address)<br />
• Returns a String containing entire content of address<br />
• Uses GET. If you want query data, URL enco<strong>de</strong> it and attach it to<br />
the end of URL after question mark<br />
–urlContentPost(String address,<br />
String ... paramNamesAndValues)<br />
• Returns a String containing entire content of address<br />
• Uses POST. All args after the first are alternating parameter<br />
names and unenco<strong>de</strong>d parameter values.
HttpUtils<br />
634<br />
jeudi 26 janvier 12<br />
public static String urlContent(String address)<br />
throws IOException, ClientProtocolException {<br />
HttpClient client = new DefaultHttpClient();<br />
HttpGet httpGet = new HttpGet(address);<br />
ResponseHandler handler =<br />
new BasicResponseHandler();<br />
return(client.execute(httpGet, handler));<br />
}
HttpUtils, Continued<br />
635<br />
jeudi 26 janvier 12<br />
public static String urlContentPost(String address,<br />
String ... paramNamesAndValues)<br />
throws IOException, ClientProtocolException {<br />
HttpClient client = new DefaultHttpClient();<br />
HttpPost httpPost = new HttpPost(address);<br />
List params = new ArrayList();<br />
for(int i=0; i
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example: Searching Web<br />
Pages for Keywords<br />
(Version 2)<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
URL Searcher<br />
• I<strong>de</strong>a<br />
–Redo the previous example, but read URL content with<br />
HttpClient instead of HttpURLConnection<br />
• Approach<br />
637<br />
jeudi 26 janvier 12<br />
–Read URL and keyword from user<br />
–Call HttpUtils.urlContent(address) to get entire content of<br />
address as a single String<br />
–Use String.split to split String on CR or LF<br />
–Test each array entry to see if it contains keyword<br />
–Reuse most of the co<strong>de</strong> from the previous example
XML Files<br />
• AndroidManifest.xml<br />
–Requests Internet permission as shown previously. Also<br />
<strong>de</strong>clares the new Activity.<br />
• res/layout/url_searcher.xml<br />
–Reuses previous layout file with no changes<br />
• Values files<br />
638<br />
jeudi 26 janvier 12<br />
–Reuses previous files with no changes<br />
• strings.xml<br />
• colors.xml<br />
• dimens.xml
Main Activity<br />
(UrlSearcher2Activity.java)<br />
public class UrlSearcher2Activity extends UrlSearcher1Activity {<br />
@Overri<strong>de</strong><br />
protected void showResults(String urlString,<br />
String searchString) {<br />
try {<br />
String urlBody = HttpUtils.urlContent(urlString);<br />
String[] lines = urlBody.split("[\\n\\r]+");<br />
StringBuil<strong>de</strong>r matches = new StringBuil<strong>de</strong>r("");<br />
int lineNum = 0;<br />
int numMatches = 0;<br />
for (String line: lines) {<br />
lineNum++;<br />
if(line.contains(searchString)) {<br />
numMatches++;<br />
matches.append(makeMatch(line, lineNum));<br />
}<br />
}<br />
displayResults(matches, numMatches);<br />
639<br />
jeudi 26 janvier 12<br />
All methods except showResults are inherited from previous class.
}<br />
Main Activity, Continued<br />
(UrlSearcher2Activity.java)<br />
640<br />
jeudi 26 janvier 12<br />
}<br />
} catch (ClientProtocolException cpe) {<br />
showError("Bad URL: " + urlString);<br />
cpe.printStackTrace(); // View this in DDMS window<br />
} catch (IOException ioe) {<br />
showError("Error in connection: " + ioe);<br />
ioe.printStackTrace(); // View this in DDMS window<br />
}
Results<br />
641<br />
jeudi 26 janvier 12<br />
I<strong>de</strong>ntical to previous example.
jeudi 26 janvier 12<br />
Asi<strong>de</strong>: JSON Format<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
JSON (JavaScript Object Notation)<br />
• I<strong>de</strong>a<br />
–A simple textual representation of (JavaScript) objects<br />
• Called “object literals” or “anonymous objects”<br />
–Main applications in JavaScript<br />
• One-time-use objects (rather than reusable classes)<br />
• Objects received via strings<br />
• Directly in JavaScript<br />
– var someObject = { property1: value1,<br />
property2: value2,<br />
... };<br />
• Wi<strong>de</strong>ly used in other languages<br />
643<br />
jeudi 26 janvier 12<br />
–Lightweight alternative to XML<br />
–Android has a builtin class (JSONObject) that will both build<br />
and parse strings representing JSON
JSON: Example in JavaScript<br />
var person =<br />
{ firstName: 'Brendan',<br />
lastName: 'Eich',<br />
bestFriend: { firstName: 'Chris',<br />
lastName: 'Wilson' },<br />
greeting: function() {<br />
return("Hi, I am " + this.firstName +<br />
" " + this.lastName + ".");<br />
}<br />
};<br />
644<br />
jeudi 26 janvier 12
Strict JSON<br />
• Object literals in JavaScript<br />
–Any way you would type a data structure into JavaScript.<br />
– { firstName: 'Larry', lastName: 'Page'}<br />
• Strict JSON according to json.org<br />
–Subset of JavaScript where:<br />
• Object property names must be in double quotes<br />
• Strings are represented with double quotes only (not single<br />
quotes)<br />
– { "firstName": "Larry", "lastName": "Page"}<br />
–This is what Android’s JSONObject supports<br />
• MIME type for JSON from server<br />
645<br />
jeudi 26 janvier 12<br />
–RFC 4627 says JSON should have "application/json" type<br />
–No known libraries enforce this
Popular Web Services that Send<br />
JSON Data<br />
• Google APIs<br />
– Search, translate, data, and many more<br />
• http://co<strong>de</strong>.google.com/apis/customsearch/v1/overview.html<br />
• Yahoo APIs<br />
– Search, travel, answers<br />
• http://<strong>de</strong>veloper.yahoo.com/<br />
• Twitter APIs<br />
– https://<strong>de</strong>v.twitter.com/<br />
• GeoNames<br />
– http://www.geonames.org/export/web-services.html<br />
• Flickr<br />
– http://www.flickr.com/services/api/<br />
• Thousands of others<br />
– See list here<br />
• http://www.programmableweb.com/apis/directory/1?format=JSON<br />
646<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
The JSONObject Class<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
JSONObject<br />
• I<strong>de</strong>a<br />
–A popular JSON-in-Java library from json.org that is bundled<br />
with Android.<br />
• Major problem: Android does not document precisely which<br />
version it uses, and the version it does use is long-obsolete and<br />
lacks JSON-from-bean capability<br />
• Capabilities<br />
648<br />
jeudi 26 janvier 12<br />
–Builds a JSONObject<br />
• From String, Map, or bean<br />
–Lets you extract data from JSONObject<br />
• getString(name), getDouble(name), etc<br />
–Lets you output string representing a JSONObject<br />
• toString
Building a JSONObject<br />
• Constructors<br />
649<br />
jeudi 26 janvier 12<br />
–new JSONObject(jsonString)<br />
• Reads a JSON string and builds JSONObject from it.<br />
– This is most important constructor for use directly on Android, since main<br />
Android use of JSON is handling JSON from Web services<br />
–new JSONObject(nameValueMap)<br />
• Takes a Map and builds JSON from it. Used on Android if you<br />
want to send JSON to a Web service<br />
–new JSONObject(bean) [not in Android version!]<br />
• Takes a bean and builds JSON based on bean properties.<br />
Cannot use directly on Android, but very useful on server that<br />
sends JSON to Android<br />
– If Android had supported this version, would have been much better way to<br />
send JSON to a Web service
Extracting Data From a<br />
JSONObject<br />
• Accessors<br />
650<br />
jeudi 26 janvier 12<br />
–get(propertyName)<br />
• Returns Object associated with name<br />
–getString(propertyName)<br />
• Returns String associated with name. Works for any type (if<br />
Object, uses its toString method)<br />
–getDouble(propertyName)<br />
• Returns double associated with name. Throws JSONException if<br />
value cannot be converted to double.<br />
–getBlah(propertyName)<br />
• getInt, getBoolean, etc. Similar in spirit to getDouble.<br />
–getJSONArray(propertyName)<br />
• Returns JSONArray (not native Java array!) associated with<br />
name
Other Capabilities<br />
• toString<br />
–Builds strict-JSON string from JSONObject<br />
• The JSONArray class<br />
651<br />
jeudi 26 janvier 12<br />
–Represents an array of JSON.<br />
–Although it can be used to send data from Android, it is<br />
usually used for received data.<br />
• { "names": ["larry", "curly", "moe"],<br />
"primes": [2, 3, 5, 7, 11] }
jeudi 26 janvier 12<br />
Using JSONObject<br />
on Server<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Steps for Servlet Outputting<br />
JSON (for Android Use)<br />
• Usual tasks<br />
– response.setContentType("application/json");<br />
– PrintWriter out = response.getWriter<br />
– Call normal business logic co<strong>de</strong> to get bean, array, or Map<br />
• New tasks<br />
653<br />
jeudi 26 janvier 12<br />
– Turn Java object into JSONObject<br />
• JSONObject result = new JSONObject(bean);<br />
• JSONArray result = new JSONArray(arrayOfBeans, false);<br />
• JSONObject result = new JSONObject(map);<br />
– Output JSONObject with print<br />
• out.print(result);<br />
– Automatically calls toString, which does the real JSONification
JSONObject’s Algorithm for<br />
JSONifying a Java Object<br />
• Find the bean properties<br />
–E.g., Name class has getFirstName, and getLastName<br />
methods, so properties are firstName and lastName<br />
• Call the associated accessor methods<br />
–Call each of getFirstName and getLastName on object<br />
• Build JSON representation<br />
–JavaScript property names are bean property names<br />
–Values are results of getter methods<br />
• Mini Example<br />
654<br />
jeudi 26 janvier 12<br />
–toString of a JSONObject representing a Name<br />
• Java: make new Name("John", "Resig").<br />
Pass to JSONObject, then call print (which uses toString)<br />
• Result: { "firstName": "John", "lastName": "Resig"}
Finding Bean Property Name<br />
Based on Method Name<br />
• Usual rule<br />
–Drop the word “get” and change the next letter to lowercase.<br />
Instance variable name is irrelevant.<br />
• Method name: getUserFirstName<br />
• Property name: userFirstName<br />
• Exception 1: boolean properties<br />
–If getter returns boolean or Boolean<br />
• Method name: getPrime or isPrime<br />
• Property name: prime<br />
• Exception 2: consecutive uppercase letters<br />
655<br />
jeudi 26 janvier 12<br />
–If two uppercase letters in a row after “get”<br />
• Method name: getURL<br />
• Property name: URL (not uRL)
Bean Properties: Examples<br />
Method Name Property Name Example JSON Output<br />
getFirstName firstName { "firstName": "Joe", … }<br />
isExecutive<br />
(boolean property)<br />
656<br />
jeudi 26 janvier 12<br />
getExecutive<br />
(boolean property)<br />
executive { "executive": true, … }<br />
executive { "executive": true, … }<br />
getZIP ZIP { "ZIP": "12345", … }<br />
Note 1: property name does not exist anywhere in your co<strong>de</strong>. It is just a shortcut for the method name.<br />
Note 2: property name is <strong>de</strong>rived only from method name. Instance variable name is irrelevant.
Steps for Using JSON Utilities:<br />
Sample Servlet Co<strong>de</strong><br />
public void doPost(HttpServletRequest request,<br />
HttpServletResponse response)<br />
throws ServletException, IOException {<br />
response.setContentType("application/json");<br />
PrintWriter out = response.getWriter();<br />
SomeBean javaResult = callSomeBusinessLogic(…);<br />
JSONObject jsonResult =<br />
new JSONObject(javaResult);<br />
out.print(jsonResult);<br />
}<br />
657<br />
jeudi 26 janvier 12<br />
Lines in red are the only ones that typically change<br />
from application to application. Other lines stay exactly as is.<br />
Calling print automatically calls toString behind the scenes
Drawbacks of JSONification<br />
• Sends state, not behavior, of object<br />
–So, properties that are <strong>de</strong>rived from other properties will be<br />
inconsistent on client if other properties are changed<br />
• Example: Java “Circle” class<br />
–getRadius<br />
• Returns instance variable<br />
–getArea<br />
• Returns Math.PI*radius*radius<br />
• JSONified instance<br />
658<br />
jeudi 26 janvier 12<br />
–Example<br />
• Make new Circle(10). Pass to JSONObject, call toString<br />
• Result: { "radius": 10.0, "area": 314.15927…}<br />
–Problem<br />
• If client-si<strong>de</strong> co<strong>de</strong> changes radius, area doesn’t match
JSONObject from Bean: Example<br />
Co<strong>de</strong><br />
public class CityTest1 {<br />
public static void main(String[] args) {<br />
City sf = CityUtils.getCity("San Francisco");<br />
JSONObject sfJSON = new JSONObject(sf);<br />
System.out.println("JSON version of SF is:\n" +<br />
sfJSON);<br />
}<br />
}<br />
659<br />
jeudi 26 janvier 12<br />
City is a simple class with a bunch of getter methods<br />
(getTime, getName, getPopulation, etc.)<br />
Note: toString is automatically called when you print an Object in Java. It is the<br />
toString method of JSONObject that builds the JSON representation.
JSONObject from Bean: Example<br />
Result<br />
JSON version of SF is:<br />
{"time": "06:00:55 AM",<br />
"name": "San Francisco",<br />
"timeZone": -3,<br />
"pop": 744041,<br />
"population": " 744,041"}<br />
660<br />
jeudi 26 janvier 12<br />
(White space ad<strong>de</strong>d for readability)
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Example:<br />
Remote Loan Calculator<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
JSON-Based Loan Calculator<br />
Service<br />
• I<strong>de</strong>a<br />
– Make servlet for doing loan calculations<br />
• Input: JSON object with amount, period, and interest rate<br />
• Output: JSON object with inputs plus monthly payment and total<br />
payments<br />
• Approach<br />
– Server<br />
• Read parameter and pass to JSONObject constructor<br />
• Extract values with getDouble and getLong<br />
• Use same PaymentInfo class as in several previous examples<br />
• Turn PaymentInfo into JSON via JSONObject<br />
– Client (Android)<br />
• Build Map and turn into JSONObject, send to server<br />
• Read String, turn into JSONObject<br />
• Extract info with getString<br />
662<br />
jeudi 26 janvier 12
Servlet<br />
@WebServlet("/loan-calculator")<br />
public class LoanCalculator extends HttpServlet {<br />
@Overri<strong>de</strong><br />
public void doGet(HttpServletRequest request, HttpServletResponse response)<br />
throws ServletException, IOException {<br />
String inputString = request.getParameter("loanInputs");<br />
double loanAmount = 200000;<br />
double annualInterestRateInPercent = 5.5;<br />
long loanPeriodInMonths = 360;<br />
try {<br />
JSONObject inputValues = new JSONObject(inputString);<br />
loanAmount = inputValues.getDouble("amount");<br />
annualInterestRateInPercent = inputValues.getDouble("rate");<br />
loanPeriodInMonths = inputValues.getLong("months");<br />
} catch (Exception e) { // NullPointerException & JSONException<br />
// Use <strong>de</strong>fault values assigned before the try block<br />
}<br />
PaymentInfo info = new PaymentInfo(loanAmount,<br />
annualInterestRateInPercent,<br />
loanPeriodInMonths);<br />
PrintWriter out = response.getWriter();<br />
out.println(new JSONObject(info));<br />
}<br />
663<br />
jeudi 26 janvier 12<br />
If you are unfamiliar with servlets, see extensive tutorial series<br />
at http://www.coreservlets.com/
Servlet, Continued<br />
664<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void doPost(HttpServletRequest request,<br />
HttpServletResponse response)<br />
throws ServletException, IOException {<br />
doGet(request, response);<br />
}<br />
Makes the most sense to send the data via POST. However, it also supports GET to simplify interactive testing by editing the browser line.<br />
This app is installed on apps.coreservlets.com, so URL is http://apps.coreservlets.com/NetworkingSupport/loan-calculator<br />
You can experiment interactively by calling<br />
http://apps.coreservlets.com/NetworkingSupport/loan-calculator?loanInputs={amount: 200000, rate: 6.5, months: 180}<br />
The tutorial Web site has the servlet co<strong>de</strong> as well as the Android co<strong>de</strong>, so you can install the servlet on a local Java server (requires Tomcat 7<br />
or equivalent). However, note that the Android emulator does not un<strong>de</strong>rstand localhost as a host name, since it acts like in<strong>de</strong>pen<strong>de</strong>nt <strong>de</strong>vice.<br />
So, you must use real domain name or IP address.
Android Activity<br />
public class LoanCalculatorActivity extends Activity {<br />
private EditText mBaseUrl, mLoanAmount, mInterestRate, mLoanPeriod;<br />
private TextView mMontlyPaymentResult, mTotalPaymentsResult;<br />
665<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.loan_calculator);<br />
mBaseUrl = (EditText)findViewById(R.id.base_url);<br />
mLoanAmount = (EditText)findViewById(R.id.loan_amount);<br />
mInterestRate = (EditText)findViewById(R.id.interest_rate);<br />
mLoanPeriod = (EditText)findViewById(R.id.loan_period);<br />
mMontlyPaymentResult =<br />
(TextView)findViewById(R.id.monthly_payment_result);<br />
mTotalPaymentsResult =<br />
(TextView)findViewById(R.id.total_payments_result);<br />
}
Android Activity, Continued<br />
666<br />
jeudi 26 janvier 12<br />
public void showLoanPayments(View clickedButton) {<br />
String baseUrl = mBaseUrl.getText().toString();<br />
String loanAmount = mLoanAmount.getText().toString();<br />
String interestRate = mInterestRate.getText().toString();<br />
String loanPeriod = mLoanPeriod.getText().toString();<br />
LoanInputs inputs =<br />
new LoanInputs(loanAmount, interestRate, loanPeriod);<br />
JSONObject inputsJson = new JSONObject(inputs.getInputMap());<br />
try {<br />
String jsonString =<br />
HttpUtils.urlContentPost(baseUrl, "loanInputs",<br />
inputsJson.toString());<br />
JSONObject jsonResult = new JSONObject(jsonString);<br />
mMontlyPaymentResult.setText<br />
(jsonResult.getString("formattedMonthlyPayment"));<br />
mTotalPaymentsResult.setText<br />
(jsonResult.getString("formattedTotalPayments"));<br />
mLoanAmount.setText<br />
(jsonResult.getString("loanAmount"));<br />
mInterestRate.setText<br />
(jsonResult.getString("annualInterestRateInPercent"));<br />
mLoanPeriod.setText<br />
(jsonResult.getString("loanPeriodInMonths"));
Helper Class<br />
public class LoanInputs {<br />
private Map mInputMap;<br />
}<br />
667<br />
jeudi 26 janvier 12<br />
public LoanInputs(String amount, String rate,<br />
String months) {<br />
mInputMap = new HashMap();<br />
mInputMap.put("amount", amount);<br />
mInputMap.put("rate", rate);<br />
mInputMap.put("months", months);<br />
}<br />
public Map getInputMap() {<br />
return(mInputMap);<br />
}
Results<br />
668<br />
jeudi 26 janvier 12<br />
http://apps.coreservlets.com/NetworkingSupport/loan-calculator
jeudi 26 janvier 12<br />
Example: Google<br />
Translation Services<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Double Translate App<br />
• I<strong>de</strong>a<br />
– The Google Translate services has a JSON-based API<br />
– http://co<strong>de</strong>.google.com/apis/language/translate/v2/using_rest.html<br />
• Can look up all the supported languages<br />
• Can translate from any supported language into any other<br />
– Translate from English to foreign and then back to English to see<br />
how well the translation works<br />
• Very good for literal text with simple grammar.<br />
• Approach<br />
– Get JSONArray representing supported lanuages.<br />
• Put in Spinner<br />
– Get JSONObject representing intermediate translation<br />
• Send back to server to get final translation<br />
– Only selected co<strong>de</strong> will be shown here. Full co<strong>de</strong> online.<br />
670<br />
jeudi 26 janvier 12
Main Activity<br />
public class DoubleTranslateActivity extends Activity {<br />
private EditText mText;<br />
private Spinner mLanguageChoices;<br />
private TextView mIntermediateResult, mFinalResult;<br />
private String apiKey = "...";<br />
671<br />
jeudi 26 janvier 12<br />
The translate API requires you to apply for<br />
a free API key and send the key with every<br />
request.
Main Activity, Continued<br />
672<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.main);<br />
mText = (EditText)findViewById(R.id.text);<br />
mLanguageChoices = (Spinner)findViewById(R.id.language_choices);<br />
List supportedLanguages =<br />
TranslateUtils.supportedLanguages(apiKey);<br />
ArrayAdapter spinner2Adapter =<br />
new ArrayAdapter(this,<br />
android.R.layout.simple_spinner_item,<br />
supportedLanguages);<br />
spinner2Adapter.setDropDownViewResource<br />
(android.R.layout.simple_spinner_dropdown_item);<br />
mLanguageChoices.setAdapter(spinner2Adapter);<br />
mIntermediateResult = (TextView)findViewById(R.id.intermediate_result);<br />
mFinalResult = (TextView)findViewById(R.id.final_result);<br />
}
Main Activity, Continued<br />
673<br />
jeudi 26 janvier 12<br />
public void doubleTranslate(View clickedButton) {<br />
String sourceLanguageCo<strong>de</strong> = "en";<br />
Language targetLanguage =<br />
(Language)mLanguageChoices.getSelectedItem();<br />
String targetLanguageCo<strong>de</strong> = targetLanguage.getCo<strong>de</strong>();<br />
String textToTranslate = mText.getText().toString();<br />
Translator translator =<br />
new Translator(apiKey, sourceLanguageCo<strong>de</strong>,<br />
targetLanguageCo<strong>de</strong>, textToTranslate);<br />
String firstTranslation = translator.getFirstTranslation();<br />
mIntermediateResult.setText(firstTranslation);<br />
String secondTranslation =<br />
translator.getSecondTranslation();<br />
mFinalResult.setText(secondTranslation);<br />
}
Key Helper Class<br />
(TranslationUtils)<br />
public static String translationString<br />
(String apiKey, String sourceLanguage,<br />
String targetLanguage, String textToTranslate) {<br />
try {<br />
String jsonString = translationJson(apiKey, sourceLanguage,<br />
targetLanguage, textToTranslate);<br />
JSONObject jsonObject = new JSONObject(jsonString);<br />
String text =<br />
jsonObject.getJSONObject("data").getJSONArray("translations")<br />
.getJSONObject(0).getString("translatedText");<br />
return(text);<br />
} catch(HttpResponseException hre) {<br />
int errorCo<strong>de</strong> = hre.getStatusCo<strong>de</strong>();<br />
if (errorCo<strong>de</strong> == 403) { // 403 is "Forbid<strong>de</strong>n"<br />
return(ERROR_FORBIDDEN);<br />
} else { // Probably 400, "Bad Request"<br />
return(ERROR_BAD_REQUEST);<br />
}<br />
} catch(IOException ioe) {<br />
return(ERROR_BAD_CONNECTION);<br />
} catch(JSONException jse) {<br />
return(ERROR_JSON_PROBLEM);<br />
}<br />
}<br />
674<br />
jeudi 26 janvier 12
Results: Very Simple Text<br />
675<br />
jeudi 26 janvier 12
Results: Medium-Difficulty Text<br />
676<br />
jeudi 26 janvier 12
Results: Deliberately-Tricky Text<br />
677<br />
jeudi 26 janvier 12<br />
The proper interpretation is “old people crew (work on) the boat”. This is an<br />
example of a gar<strong>de</strong>n-path sentence and is taken from http://<br />
en.wikipedia.org/wiki/Gar<strong>de</strong>n_path_sentence
Results: More Deliberately-Tricky<br />
Text<br />
678<br />
jeudi 26 janvier 12<br />
The proper interpretation is “baby <strong>de</strong>er die when hunters (who are in the<br />
burning forest) shoot at them”.
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
More Reading<br />
• JavaDoc<br />
–HttpURLConnection<br />
• http://<strong>de</strong>veloper.android.com/reference/java/net/<br />
HttpURLConnection.html<br />
• HttpClient Tutorial<br />
–http://hc.apache.org/httpclient-3.x/tutorial.html<br />
• JSON Tutorials<br />
680<br />
jeudi 26 janvier 12<br />
–http://json.org/<br />
–http://www.webmonkey.com/2010/02/<br />
get_started_with_json/<br />
–http://www.hunlock.com/blogs/<br />
Mastering_JSON_(_JavaScript_Object_Notation_)
Summary<br />
• Read individual lines from a URL<br />
–Use HttpURLConnection<br />
• Read an entire URL as a String<br />
–Use HttpClient<br />
• Particularly useful if result is JSON<br />
• JSON<br />
–Simple format wi<strong>de</strong>ly used in Ajax and Web services<br />
• JSONObject<br />
681<br />
jeudi 26 janvier 12<br />
–Converts string into JSON<br />
–Outputs JSON string<br />
• But builtin Android version lacks most important method, for<br />
building JSON string from a bean
jeudi 26 janvier 12<br />
Multithrea<strong>de</strong>d Programming<br />
Part I: General Techniques<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• Why threads?<br />
• Basic approach<br />
–Make a task list with Executors.newFixedThreadPool<br />
–Add tasks to list with taskList.execute(someRunnable)<br />
• Three variations on the theme<br />
–Separate classes that implement Runnable<br />
–Main Activity implements Runnable<br />
–Inner classes that implement Runnable<br />
• Related topics<br />
683<br />
jeudi 26 janvier 12<br />
–Race conditions and synchronization<br />
–Helpful Thread-related methods<br />
–Advanced topics in concurrency
684<br />
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Motivation for Concurrent<br />
Programming<br />
• Pros<br />
–Advantages even on single-processor systems<br />
• Efficiency<br />
– Downloading image files<br />
• Convenience<br />
– A clock icon<br />
• Responsiveness<br />
– If you block the main thread, event handlers will not respond<br />
–Some <strong>de</strong>vices have multiple cpus or cores<br />
• Find out via Runtime.getRuntime().availableProcessors()<br />
• Cons<br />
685<br />
jeudi 26 janvier 12<br />
–Significantly har<strong>de</strong>r to <strong>de</strong>bug and maintain than single-<br />
threa<strong>de</strong>d apps
Steps for<br />
Concurrent Programming<br />
• First, make a task list<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(poolSize);<br />
• The poolSize is the maximum number of simultaneous threads. For<br />
many apps, it is higher than the number of tasks, so each task has a<br />
separate thread.<br />
• There are other types of thread pools, but this is simplest<br />
• Second, add tasks to the list (three options)<br />
– Make a separate class that implements Runnable.<br />
• Make instances of this class and start threading via<br />
taskList.execute(new MySeparateRunnableClass(…))<br />
– Have your existing class implement Runnable.<br />
• Start threading via taskList.execute(this)<br />
– Use an inner class.<br />
• taskList.execute(new MyInnerRunnableClass(…))<br />
686<br />
jeudi 26 janvier 12
687<br />
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Approach One: Separate<br />
Classes that Implement<br />
Runnable<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Thread Mechanism One:<br />
Separate Runnable Class<br />
• Make class that implements Runnable<br />
–No import statements nee<strong>de</strong>d: Runnable is in java.lang<br />
• Put actions to be performed in run method<br />
–public class MyRunnableClass implements Runnable {<br />
}<br />
public void run() { … }<br />
• Create instance of your class<br />
–Or lots of instances if you want lots of threads<br />
• Pass instance to ExecutorService.execute<br />
688<br />
jeudi 26 janvier 12<br />
–taskList.execute(new MyRunnableClass(…));<br />
• The number of simultaneous threads won’t exceed the maximum<br />
size of the pool.
Separate Runnable Class:<br />
Template Co<strong>de</strong><br />
689<br />
jeudi 26 janvier 12<br />
public class MainClass extends Activity {<br />
...<br />
public void startSomeThreads() {<br />
int poolSize = ...;<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(poolSize);<br />
for(int i=0; i
Thread Mechanism One: Example<br />
public class ThreadingBasicsActivity extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.threading_basics);<br />
}<br />
}<br />
690<br />
jeudi 26 janvier 12<br />
public void separateClass(View clickedButton) {<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(50);<br />
taskList.execute(new SeparateCounter(6));<br />
taskList.execute(new SeparateCounter(5));<br />
taskList.execute(new SeparateCounter(4));<br />
}<br />
This method is associated with<br />
a Button via the<br />
android:onClick attribute in the<br />
layout file.
Thread Mechanism One: Example<br />
(Continued)<br />
public class SeparateCounter implements Runnable {<br />
private final int mLoopLimit;<br />
}<br />
691<br />
jeudi 26 janvier 12<br />
public SeparateCounter(int loopLimit) {<br />
this.mLoopLimit = loopLimit;<br />
}<br />
public void run() {<br />
for (int i = 0; i < mLoopLimit; i++) {<br />
String threadName =<br />
Thread.currentThread().getName();<br />
System.out.printf("%s: %s%n", threadName, i);<br />
// Sleep for up to 1 second<br />
ThreadUtils.pause(Math.random());<br />
}<br />
}<br />
This example is just for testing, so the output will go in the DDMS window. The next tutorial section will talk about what to do if<br />
the results of the background threads directly affect the user interface.
Helper Class<br />
public class ThreadUtils {<br />
public static void pause(double seconds) {<br />
try {<br />
Thread.sleep(Math.round(1000.0 * seconds));<br />
} catch (InterruptedException ie) {}<br />
}<br />
}<br />
692<br />
jeudi 26 janvier 12<br />
// Uninstantiable class: static methods only<br />
private ThreadUtils() {}
Thread Mechanism One: Results<br />
pool-2-thread-1: 0<br />
pool-2-thread-2: 0<br />
pool-2-thread-3: 0<br />
pool-2-thread-1: 1<br />
pool-2-thread-3: 1<br />
pool-2-thread-3: 2<br />
pool-2-thread-2: 1<br />
pool-2-thread-3: 3<br />
pool-2-thread-1: 2<br />
pool-2-thread-2: 2<br />
pool-2-thread-2: 3<br />
pool-2-thread-1: 3<br />
pool-2-thread-1: 4<br />
pool-2-thread-1: 5<br />
pool-2-thread-2: 4<br />
693<br />
jeudi 26 janvier 12
Pros and Cons of Approach<br />
• Advantages<br />
– Loose coupling<br />
• Can change pieces in<strong>de</strong>pen<strong>de</strong>ntly<br />
• Can reuse Runnable class in more than one application<br />
– Passing arguments<br />
• If you want different threads to do different things, you pass args to<br />
constructor, which stores them in instance variables that run method uses<br />
– Little danger of race conditions<br />
• You usually use this approach when there is no data shared among<br />
threads, so no need to synchronize.<br />
• Disadvantages<br />
– Hard to access main Activity<br />
• If you want to call methods in main app, you must<br />
694<br />
jeudi 26 janvier 12<br />
– Pass reference to main app to the Runnable’s constructor, which stores it<br />
– Make methods in main app be public
695<br />
jeudi 26 janvier 12<br />
Approach Two: Main<br />
App Implements<br />
Runnable<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Review of Interfaces: Syntax<br />
• Shape interface<br />
public interface Shape {<br />
}<br />
public double getArea(); // No body, just specification<br />
• Circle class<br />
public class Circle implements Shape {<br />
}<br />
• Note<br />
696<br />
jeudi 26 janvier 12<br />
public double getArea() { some real co<strong>de</strong> }<br />
–You can implement many interfaces<br />
• public class MyClass implements Foo, Bar, Baz { … }
Review of Interfaces: Benefits<br />
• Class can be treated as interface type<br />
697<br />
jeudi 26 janvier 12<br />
–public interface Shape {<br />
public double getArea();<br />
}<br />
–public class Circle implements Shape { … }<br />
–public class Rectangle implements Shape { … }<br />
Shape[] shapes =<br />
{ new Circle(…), new Rectangle(…) … };<br />
double sum = 0;<br />
for(Shape s: shapes) {<br />
sum = sum + s.getArea(); // All Shapes have getArea<br />
}
Thread Mechanism Two:<br />
Main App Implements Runnable<br />
• Have main class implement Runnable<br />
– Put actions in run method of existing class<br />
• public class MyClass extends Activity implements Runnable {<br />
…<br />
public void run() { … }<br />
}<br />
• Pass the instance of main class to execute<br />
– taskList.execute(this);<br />
• Main differences from previous approach<br />
– Good<br />
• run can easily call methods in main class, since it is in that class<br />
– Bad<br />
• If run accesses any shared data (instance variables), you have to<br />
worry about conflicts (race conditions)<br />
• Very hard to pass arguments, so each task starts off the same<br />
698<br />
jeudi 26 janvier 12
Main App Implements Runnable:<br />
Template Co<strong>de</strong><br />
699<br />
public class Threa<strong>de</strong>dActivity extends Activity<br />
implements Runnable {<br />
public void run() {<br />
// Co<strong>de</strong> to run in background. Don’t update UI.<br />
}<br />
}<br />
jeudi 26 janvier 12<br />
public void startSomeThreads() {<br />
int poolSize = ...;<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(poolSize);<br />
for(int i=0; i
Thread Mechanism Two: Example<br />
public class ThreadingBasicsActivity extends Activity<br />
implements Runnable {<br />
private final static int LOOP_LIMIT = 5;<br />
700<br />
jeudi 26 janvier 12<br />
public void implementsInterface(View clickedButton) {<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(50);<br />
taskList.execute(this);<br />
taskList.execute(this);<br />
}<br />
taskList.execute(this);<br />
This method is associated with<br />
a Button via the<br />
android:onClick attribute in the<br />
layout file.<br />
@Overri<strong>de</strong><br />
public void run() {<br />
for (int i = 0; i < LOOP_LIMIT; i++) {<br />
String threadName = Thread.currentThread().getName();<br />
System.out.printf("%s: %s%n", threadName, i);<br />
ThreadUtils.pause(Math.random());<br />
}<br />
}
Thread Mechanism Two: Results<br />
pool-3-thread-1: 0<br />
pool-3-thread-2: 0<br />
pool-3-thread-3: 0<br />
pool-3-thread-3: 1<br />
pool-3-thread-1: 1<br />
pool-3-thread-2: 1<br />
pool-3-thread-1: 2<br />
pool-3-thread-3: 2<br />
pool-3-thread-2: 2<br />
pool-3-thread-3: 3<br />
pool-3-thread-1: 3<br />
pool-3-thread-3: 4<br />
pool-3-thread-2: 3<br />
pool-3-thread-1: 4<br />
pool-3-thread-2: 4<br />
701<br />
jeudi 26 janvier 12
Pros and Cons of Approach<br />
• Advantages<br />
–Easy to access main app.<br />
• The run method is already insi<strong>de</strong> main app. Can access any<br />
public or private methods or instance variables.<br />
• Disadvantages<br />
702<br />
jeudi 26 janvier 12<br />
–Tight coupling<br />
• run method tied closely to this application<br />
–Cannot pass arguments to run<br />
• So, you either start a single thread only (quite common), or all<br />
the threads do very similar tasks<br />
–Danger of race conditions<br />
• You usually use this approach specifically because you want to<br />
access data in main application. So, if run modifies some shared<br />
data, you must synchronize.
703<br />
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Approach Three: Inner<br />
Class that Implements<br />
Runnable<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Review of Inner Classes<br />
• Class can be <strong>de</strong>fined insi<strong>de</strong> another class<br />
– Methods in the inner class can access all methods and instance<br />
variables of surrounding class<br />
• Even private methods and variables<br />
• Example<br />
public class OuterClass {<br />
private int count = …;<br />
704<br />
jeudi 26 janvier 12<br />
}<br />
public void foo(…) {<br />
InnerClass inner = new InnerClass();<br />
inner.bar();<br />
}<br />
private class InnerClass {<br />
public void bar() {<br />
doSomethingWith(count);<br />
}<br />
}
Thread Mechanism Three:<br />
Runnable Inner Class<br />
• Have inner class implement Runnable<br />
–Put actions in run method of inner class<br />
• public class MyClass extends Activity {<br />
…<br />
private class SomeInnerClass implements Runnable {<br />
public void run() { … }<br />
}<br />
}<br />
• Pass instances of inner class to execute<br />
705<br />
jeudi 26 janvier 12<br />
–taskList.execute(new SomeInnerClass(…));
Inner Class Implements<br />
Runnable: Template Co<strong>de</strong><br />
706<br />
jeudi 26 janvier 12<br />
public class MainClass extends Activity {<br />
public void startSomeThreads() {<br />
int poolSize = ...;<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(poolSize);<br />
for(int i=0; i
Thread Mechanism Three:<br />
Example<br />
public class ThreadingBasicsActivity extends Activity {<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.threading_basics);<br />
}<br />
707<br />
jeudi 26 janvier 12<br />
public void innerClass(View clickedButton) {<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(50);<br />
taskList.execute(new InnerCounter(6));<br />
taskList.execute(new InnerCounter(5));<br />
taskList.execute(new InnerCounter(4));<br />
}<br />
This method is associated with a Button via the<br />
android:onClick attribute in the layout file. Note<br />
also that the class is not yet finished – inner class<br />
on next page is still insi<strong>de</strong> this class.
}<br />
Thread Mechanism Three:<br />
Example (Continued)<br />
708<br />
jeudi 26 janvier 12<br />
private class InnerCounter implements Runnable {<br />
private final int mLoopLimit;<br />
}<br />
public InnerCounter(int loopLimit) {<br />
this.mLoopLimit = loopLimit;<br />
}<br />
public void run() {<br />
for (int i = 0; i < mLoopLimit; i++) {<br />
String threadName =<br />
Thread.currentThread().getName();<br />
System.out.printf("%s: %s%n", threadName, i);<br />
ThreadUtils.pause(Math.random());<br />
}<br />
}<br />
You can also use anonymous inner classes. This is not different enough to warrant a separate<br />
example here, especially since we showed examples in the section on Widget event handling.
Thread Mechanism Three:<br />
Results<br />
pool-5-thread-1: 0<br />
pool-5-thread-2: 0<br />
pool-5-thread-3: 0<br />
pool-5-thread-3: 1<br />
pool-5-thread-1: 1<br />
pool-5-thread-2: 1<br />
pool-5-thread-1: 2<br />
pool-5-thread-1: 3<br />
pool-5-thread-3: 2<br />
pool-5-thread-2: 2<br />
pool-5-thread-2: 3<br />
pool-5-thread-3: 3<br />
pool-5-thread-1: 4<br />
pool-5-thread-2: 4<br />
pool-5-thread-1: 5<br />
709<br />
jeudi 26 janvier 12
Pros and Cons of Approach<br />
• Advantages<br />
–Easy to access main app.<br />
• Methods in inner classes can access any public or private<br />
methods or instance variables of outer class.<br />
–Can pass arguments to run<br />
• As with separate classes, you pass args to constructor, which<br />
stores them in instance variables that run uses<br />
• Disadvantages<br />
710<br />
jeudi 26 janvier 12<br />
–Tight coupling<br />
• run method tied closely to this application<br />
–Danger of race conditions<br />
• You usually use this approach specifically because you want to<br />
access data from main application. So, if run modifies some<br />
shared data, you must synchronize.
711<br />
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Summary of Approaches<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Pros and Cons<br />
• Separate class that implements Runnable<br />
–Can pass args to run<br />
–Cannot easily access data in main class<br />
–Usually no worry about race conditions<br />
• Main class implements Runnable<br />
–Can easily access data in main class<br />
–Cannot pass args to run<br />
–Must worry about race conditions<br />
• Inner class implements Runnable<br />
712<br />
jeudi 26 janvier 12<br />
–Can easily access data in main class<br />
–Can pass args to run<br />
–Must worry about race conditions
713<br />
jeudi 26 janvier 12<br />
Race Conditions and<br />
Synchronization<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Race Conditions<br />
• I<strong>de</strong>a<br />
– You write co<strong>de</strong> that assumes no other threads run between certain<br />
steps. But, if your thread is interrupted in the wrong place and<br />
another thread changes some data, you get the wrong answer.<br />
• Typical scenarios<br />
– You modify shared data & assume next thread sees new result.<br />
• You read a value and then increment it. You assume no thread runs<br />
between when you read it and when you increment it.<br />
– You read shared data and then use it, forgetting that it could<br />
change between when you read it and when you use it<br />
• You look up size of a List, then loop from 0 to size-1. But, another<br />
thread could remove elements in between.<br />
714<br />
jeudi 26 janvier 12
Race Conditions: Example<br />
public class RaceConditionsActivity extends Activity<br />
implements Runnable {<br />
private final static int LOOP_LIMIT = 3;<br />
private final static int POOL_SIZE = 4;<br />
private int mLatestThreadNum = 0;<br />
715<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.race_conditions);<br />
}<br />
public void tryRace(View clickedButton) {<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(POOL_SIZE);<br />
for(int i=0; i
}<br />
Race Conditions: Example<br />
(Continued)<br />
public void run() {<br />
int currentThreadNum = mLatestThreadNum;<br />
System.out.printf("Setting currentNum to %s%n",<br />
currentThreadNum);<br />
mLatestThreadNum = mLatestThreadNum + 1;<br />
for (int i = 0; i < LOOP_LIMIT; i++) {<br />
System.out.printf("I am Counter %s; i is %s%n",<br />
currentThreadNum, i);<br />
ThreadUtils.pause(0.5 * Math.random());<br />
}<br />
}<br />
• What’s wrong with this co<strong>de</strong>?<br />
716<br />
jeudi 26 janvier 12
Race Conditions: Result<br />
• Usual Output<br />
Setting currentNum to 0<br />
I am Counter 0; i is 0<br />
Setting currentNum to 1<br />
I am Counter 1; i is 0<br />
Setting currentNum to 2<br />
I am Counter 2; i is 0<br />
Setting currentNum to 3<br />
I am Counter 3; i is 0<br />
I am Counter 0; i is 1<br />
I am Counter 2; i is 1<br />
I am Counter 3; i is 1<br />
I am Counter 1; i is 1<br />
I am Counter 0; i is 2<br />
I am Counter 1; i is 2<br />
I am Counter 3; i is 2<br />
I am Counter 2; i is 2<br />
717<br />
jeudi 26 janvier 12<br />
• Occasional Output<br />
Setting currentNum to 36<br />
I am Counter 36; i is 0<br />
Setting currentNum to 37<br />
I am Counter 37; i is 0<br />
Setting currentNum to 38<br />
Setting currentNum to 38<br />
I am Counter 38; i is 0<br />
I am Counter 38; i is 0<br />
I am Counter 36; i is 1<br />
I am Counter 38; i is 1<br />
I am Counter 37; i is 1<br />
I am Counter 38; i is 1<br />
I am Counter 36; i is 2<br />
I am Counter 38; i is 2<br />
I am Counter 37; i is 2<br />
I am Counter 38; i is 2
Race Conditions: Solution?<br />
• Do things in a single step<br />
718<br />
jeudi 26 janvier 12<br />
public void run() {<br />
int currentThreadNum = mLatestThreadNum++;<br />
System.out.printf("Setting currentNum to %s%n",<br />
currentThreadNum);<br />
for (int i = 0; i < LOOP_LIMIT; i++) {<br />
System.out.printf("I am Counter %s; i is %s%n",<br />
currentThreadNum, i);<br />
ThreadUtils.pause(0.5 * Math.random());<br />
}<br />
}<br />
This “solution” does not fix the problem. In some ways, it makes it worse!
Arbitrating Contention for Shared<br />
Resources<br />
• Synchronizing a section of co<strong>de</strong><br />
synchronized(someObject) {<br />
co<strong>de</strong><br />
}<br />
• Fixing the previous race condition<br />
public void run() {<br />
int currentThreadNum;<br />
synchronized(this) {<br />
currentThreadNum = mLatestThreadNum;<br />
System.out.printf("Setting currentNum to %s%n",<br />
currentThreadNum);<br />
mLatestThreadNum = mLatestThreadNum + 1;<br />
}<br />
for (int i = 0; i < LOOP_LIMIT; i++) {<br />
...<br />
}<br />
}<br />
719<br />
jeudi 26 janvier 12
Arbitrating Contention for Shared<br />
Resources<br />
• Synchronizing a section of co<strong>de</strong><br />
synchronized(someObject) {<br />
co<strong>de</strong><br />
}<br />
• Simplistic interpretation<br />
–Once a thread enters the co<strong>de</strong>, no other thread can enter until<br />
the first thread exits.<br />
• Stronger interpretation<br />
720<br />
jeudi 26 janvier 12<br />
–Once a thread enters the co<strong>de</strong>, no other thread can enter any<br />
section of co<strong>de</strong> that is synchronized using the same “lock”<br />
object<br />
• If two pieces of co<strong>de</strong> say “synchronized(blah)”, the question is if<br />
the blah’s are the same object instance.
Arbitrating Contention for Shared<br />
Resources<br />
• Synchronizing an entire method<br />
public synchronized void someMethod() {<br />
body<br />
}<br />
• Note that this is equivalent to<br />
721<br />
jeudi 26 janvier 12<br />
public void someMethod() {<br />
synchronized(this) {<br />
body<br />
}<br />
}
722<br />
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Helpful Thread-Related<br />
Methods<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Methods in Thread Class<br />
• Thread.currentThread()<br />
–Gives instance of Thread that is running current co<strong>de</strong><br />
• Thread.sleep(milliseconds)<br />
–Puts calling co<strong>de</strong> to sleep. Useful for non-busy waiting in all<br />
kinds of co<strong>de</strong>, not just multithrea<strong>de</strong>d co<strong>de</strong>. You must catch<br />
InterruptedException, but you can ignore it:<br />
• try { Thread.sleep(someMilliseconds); }<br />
catch (InterruptedException ie) { }<br />
–See also TimeUnit.SECONDS.sleep,<br />
TimeUnit.MINUTES.sleep, etc.<br />
• Same i<strong>de</strong>a except takes sleep time in different units.<br />
• someThread.getName(), someThread.getId()<br />
723<br />
jeudi 26 janvier 12<br />
–Useful for printing/<strong>de</strong>bugging, to tell threads apart
Methods in ExecutorService<br />
Class<br />
• execute(Runnable)<br />
– Adds Runnable to the queue of tasks<br />
• shutdown<br />
– Prevents any more tasks from being ad<strong>de</strong>d with execute (or<br />
submit), but lets current tasks finish.<br />
• shutdownNow<br />
– Attempts to halt current tasks. But author of tasks must have them<br />
respond to interrupts (ie, catch InterruptedException), or this is<br />
no different from shutdown.<br />
• awaitTermination<br />
– Blocks until all tasks are complete. Must shutdown() first.<br />
• submit, invokeAny, invokeAll<br />
– Variations that use Callable instead of Runnable. See next sli<strong>de</strong><br />
on Callable.<br />
724<br />
jeudi 26 janvier 12
Callable<br />
• Runnable<br />
–“run” method runs in background. No return values, but run<br />
can do si<strong>de</strong> effects.<br />
–Use “execute” to put in task queue<br />
• Callable<br />
725<br />
jeudi 26 janvier 12<br />
–“call” method runs in background. It returns a value that can<br />
be retrieved after termination with “get”.<br />
–Use “submit” to put in task queue.<br />
–Use invokeAny and invokeAll to block until value or values<br />
are available<br />
• Example: you have a list of links from a Web page and want to<br />
check status (404 vs. good). Submit them to a task queue to run<br />
concurrently, then invokeAll will let you see return values when<br />
all links are done being checked.
Lower-Level Threading<br />
• Use Thread.start(someRunnable)<br />
– Implement Runnable, pass to Thread constructor, call start<br />
• Thread t = new Thread(someRunnable);<br />
• t.start();<br />
– About same effect as taskList.execute(someRunnable), except<br />
that you cannot put bound on number of simultaneous threads.<br />
– Mostly a carryover from pre-Java-5 days; still wi<strong>de</strong>ly used.<br />
• Extend Thread<br />
– Put run method in Thread subclass, instantiate, call start<br />
• SomeThreadSubclass t = new SomeThreadSubclass(…);<br />
• t.start();<br />
– A holdover from pre-Java-5; has little use in mo<strong>de</strong>rn Java<br />
applications (Android or otherwise)<br />
726<br />
jeudi 26 janvier 12
727<br />
jeudi 26 janvier 12<br />
Advanced Topics<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Types of Task Queues<br />
• Executors.newFixedThreadPool(nThreads)<br />
– Simplest and most wi<strong>de</strong>ly used type. Makes a list of tasks to be run in the<br />
background, but with caveat that there are never more than nThreads<br />
simultaneous threads running.<br />
• Executors.newScheduledThreadPool<br />
– Lets you <strong>de</strong>fine tasks that run after a <strong>de</strong>lay, or that run periodically.<br />
Replacement for pre-Java-5 “Timer” class.<br />
• Executors.newCachedThreadPool<br />
– Optimized version for apps that start many short-running threads. Reuses<br />
thread instances.<br />
• Executors.newSingleThreadExecutor<br />
– Makes queue of tasks and executes one at a time<br />
• ExecutorService (subclass) constructors<br />
– Lets you build FIFO, LIFO, and priority queues<br />
728<br />
jeudi 26 janvier 12
Stopping a Thread<br />
public class SomeTask implements Runnable {<br />
private volatile boolean running;<br />
}<br />
729<br />
jeudi 26 janvier 12<br />
public void run(){<br />
running = true;<br />
while (running) {<br />
...<br />
}<br />
doCleanup();<br />
}<br />
public void setRunning(boolean running) {<br />
this.running = running;<br />
}<br />
Compilers on multicore systems often do optimizations that prevent changes to<br />
variables from one thread from being seen by another thread. To guarantee that<br />
other threads see your changes, either use synchronized methods, <strong>de</strong>clare the<br />
variable “volatile”, or use AtomicBoolean.
Nasty Synchronization Bug<br />
public class Driver {<br />
public void startThreads() {<br />
…<br />
for(…) {<br />
taskList.execute(new SomeThrea<strong>de</strong>dClass());<br />
}}}<br />
public class SomeThrea<strong>de</strong>dClass implements Runnable {<br />
public synchronized void doSomeOperation() {<br />
accessSomeSharedObject();<br />
}<br />
...<br />
public void run() {<br />
while(someCondition) {<br />
doSomeOperation(); // Accesses shared data<br />
doSomeOtherOperation();// No shared data<br />
}<br />
}<br />
}<br />
730<br />
jeudi 26 janvier 12
Synchronization Solution<br />
• Solution 1: synchronize on the shared data<br />
public void doSomeOperation() {<br />
synchronized(someSharedObject) {<br />
accessSomeSharedObject();<br />
}<br />
}<br />
• Solution 2: synchronize on the class object<br />
public void doSomeOperation() {<br />
synchronized(SomeThrea<strong>de</strong>dClass.class) {<br />
accessSomeSharedObject();<br />
}<br />
}<br />
731<br />
jeudi 26 janvier 12<br />
– Note that if you synchronize a static method, the lock is the<br />
corresponding Class object, not this
Synchronization Solution<br />
(Continued)<br />
• Solution 3: synchronize on arbitrary object<br />
732<br />
jeudi 26 janvier 12<br />
public class SomeThrea<strong>de</strong>dClass<br />
implements Runnable{<br />
private static Object lockObject<br />
= new Object();<br />
...<br />
public void doSomeOperation() {<br />
synchronized(lockObject) {<br />
accessSomeSharedObject();<br />
}<br />
}<br />
...<br />
}<br />
– Why doesn’t this problem usually occur with thread mechanism<br />
two (with run method in main class)?
Determining Maximum Thread<br />
Pool Size<br />
• In most apps, a reasonable guess is fine<br />
int maxThreads = 50;<br />
ExecutorService tasks =<br />
Executors.newFixedThreadPool(maxThreads);<br />
• For more precision, you can use equation<br />
733<br />
jeudi 26 janvier 12<br />
maxThreads = numCpus * targetUtilization *<br />
(1 + avgWaitTime/avgComputeTime)<br />
• Compute numCpus with<br />
Runtime.getRuntime().availableProcessors()<br />
• targetUtilization is from 0.0 to 1.0<br />
• Find ratio of wait to compute time with profiling<br />
• Equation taken from Java Concurrency in Practice
Other Advanced Topics<br />
• wait/waitForAll<br />
– Releases the lock for other threads and suspends itself (placed in a wait<br />
queue associated with the lock)<br />
– Very important in some applications, but very, very hard to get right. Try<br />
to use the newer Executor services if possible.<br />
• notify/notifyAll<br />
– Wakes up all threads waiting for the lock<br />
– A notified thread doesn’t begin immediate execution, but is placed in the<br />
runnable thread queue<br />
• Concurrency utilities in java.util.concurrency<br />
– Advanced threading utilities including semaphores, collections <strong>de</strong>signed<br />
for multithrea<strong>de</strong>d applications, atomic operations, etc.<br />
• Debugging thread problems<br />
– Use JConsole (bundled with Java 5; officially part of Java 6)<br />
• http://java.sun.com/<strong>de</strong>veloper/technicalArticles/J2SE/jconsole.html<br />
734<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
More Reading<br />
• Books<br />
–Java Concurrency in Practice (Goetz, et al)<br />
–Chapter 10 (“Concurrency”) of Effective Java, 2 nd Ed (Josh<br />
Bloch)<br />
• Effective Java is the alltime best Java practices book<br />
–Java Threads (Oak and Wong)<br />
• Online references<br />
736<br />
jeudi 26 janvier 12<br />
–Lesson: Concurrency (Oracle Java Tutorial)<br />
• http://download.oracle.com/javase/tutorial/essential/concurrency/<br />
–Jacob Jenkov’s Concurrency Tutorial<br />
• http://tutorials.jenkov.com/java-concurrency/in<strong>de</strong>x.html<br />
–Lars Vogel’s Concurrency Tutorial<br />
• http://www.vogella.<strong>de</strong>/articles/JavaConcurrency/article.html
Summary<br />
• Basic approach<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(poolSize);<br />
• Three variations<br />
–taskList.execute(new SeparateClass(…));<br />
–taskList.execute(this);<br />
–taskList.execute(new InnerClass(…));<br />
• Handling shared data<br />
737<br />
jeudi 26 janvier 12<br />
synchronized(referenceSharedByThreads) {<br />
}<br />
getSharedData();<br />
modifySharedData();<br />
doOtherStuff();
jeudi 26 janvier 12<br />
© 2011 Marty Hall<br />
Multithrea<strong>de</strong>d Programming Part II:<br />
Android-Specific Techniques<br />
Originals of Sli<strong>de</strong>s and Source Co<strong>de</strong> for Examples:<br />
http://www.coreservlets.com/android-tutorial/<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Topics in This Section<br />
• GUI update gui<strong>de</strong>lines<br />
• Updating UI after threads complete<br />
• Downloading images from Internet<br />
• Updating UI with View.post<br />
• Updating UI with AsyncTask<br />
739<br />
jeudi 26 janvier 12
740<br />
jeudi 26 janvier 12<br />
Overview<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Issues<br />
• Nonresponsive GUI controls<br />
–Long-running co<strong>de</strong> in main thread will make GUI controls<br />
nonresponsive.<br />
• Threads cannot update user interface<br />
741<br />
jeudi 26 janvier 12<br />
–Background threads are prohibited from updating UI.
Nonresponsive GUI Controls<br />
• Problem<br />
–Long-running co<strong>de</strong> in main thread will make GUI controls<br />
nonresponsive.<br />
• For example, if a Button’s onClick handler takes 5 seconds, then<br />
none of the other controls will respond for 5 seconds.<br />
• Solution<br />
742<br />
jeudi 26 janvier 12<br />
–Move time-consuming operations to background threads<br />
• This was the entire point of the previous lecture on the basics of<br />
multithrea<strong>de</strong>d programming
Threads Cannot Update UI<br />
• Problem<br />
– Background threads are prohibited from updating UI.<br />
• E.g., background threads cannot add a new View to the display, nor can<br />
they call setText on a visible View.<br />
• Solutions (alternatives)<br />
– Wait until all threads are done, then update UI<br />
743<br />
jeudi 26 janvier 12<br />
• When multithreading improves performance, but total wait time is small<br />
– Have background threads use View.post to send UI-updating operations<br />
back to UI thread<br />
• Especially when transitioning standard threading co<strong>de</strong> to Android<br />
– Use AsyncTask to divi<strong>de</strong> tasks between background and UI threads<br />
• Especially when <strong>de</strong>veloping for Android from beginning and you have a lot<br />
of incremental GUI updates.
jeudi 26 janvier 12<br />
Updating UI After<br />
Threads Complete<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Updating UI All at Once<br />
• Scenario<br />
–Using threads improves performance.<br />
–Total wait time is small, so no need to display intermediate<br />
results.<br />
• Approach<br />
745<br />
jeudi 26 janvier 12<br />
–Add threads to ExecutorService task list.<br />
–Use awaitTermination to wait until all tasks are finished (or a<br />
timeout is excee<strong>de</strong>d)<br />
–Update UI. You are in UI thread, so this is safe/legal.
Example: Multi-URL Validator<br />
• I<strong>de</strong>a<br />
–Let user enter any number of URLs<br />
–Check if they are legal by making HTTP HEAD requests and<br />
checking the server status line<br />
• Approach<br />
746<br />
jeudi 26 janvier 12<br />
–Make a List of URL result hol<strong>de</strong>rs<br />
–For each URL, pass result hol<strong>de</strong>r to background thread.<br />
Background thread stores result in hol<strong>de</strong>r. Use inner class for<br />
background thread implementation.<br />
–After all tasks are complete or 10 seconds have elapsed<br />
(whichever is sooner), show results in ScrollView
Main Activity: Setup Co<strong>de</strong><br />
public class UrlCheckerActivity extends Activity {<br />
private LinearLayout mResultsRegion;<br />
private EditText mUrlsToTest;<br />
private int mGoodUrlColor, mForwar<strong>de</strong>dUrlColor,<br />
mBadUrlColor;<br />
private Drawable mGoodUrlIcon, mForwar<strong>de</strong>dUrlIcon,<br />
mBadUrlIcon;<br />
List mResultsHol<strong>de</strong>r =<br />
new ArrayList();<br />
private final static int HEAD_TIMEOUT = 10;<br />
private float mResultTextSize;<br />
private int mResultPaddingSize;<br />
747<br />
jeudi 26 janvier 12
Main Activity: Setup Co<strong>de</strong><br />
(Continued)<br />
748<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.url_checker);<br />
mUrlsToTest = (EditText)findViewById(R.id.urls_to_test);<br />
mResultsRegion = (LinearLayout)findViewById(R.id.results_region);<br />
Resources resources = getResources();<br />
mGoodUrlColor = resources.getColor(R.color.url_good);<br />
mForwar<strong>de</strong>dUrlColor = resources.getColor(R.color.url_forwar<strong>de</strong>d);<br />
mBadUrlColor = resources.getColor(R.color.url_bad);<br />
mGoodUrlIcon = resources.getDrawable(R.drawable.emo_im_happy);<br />
mForwar<strong>de</strong>dUrlIcon = resources.getDrawable(R.drawable.emo_im_wtf);<br />
mBadUrlIcon = resources.getDrawable(R.drawable.emo_im_sad);<br />
mResultTextSize =<br />
resources.getDimension(R.dimen.url_checker_result_size);<br />
mResultPaddingSize =<br />
(int)resources.getDimension(R.dimen.url_checker_padding_size);
Main Activity: Button Handler<br />
(Starts Threads)<br />
749<br />
jeudi 26 janvier 12<br />
public void checkUrls(View clickedButton) {<br />
mResultsRegion.removeAllViews();<br />
mResultsRegion.requestLayout();<br />
String[] urls =<br />
mUrlsToTest.getText().toString().split("\\s+");<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(50);<br />
for (String url: urls) {<br />
UrlCheckerResult resultHol<strong>de</strong>r =<br />
new UrlCheckerResult(url);<br />
mResultsHol<strong>de</strong>r.add(resultHol<strong>de</strong>r);<br />
taskList.execute(new UrlTester(resultHol<strong>de</strong>r));<br />
}<br />
try {<br />
taskList.shutdown();<br />
taskList.awaitTermination(HEAD_TIMEOUT,<br />
TimeUnit.SECONDS);<br />
} catch (InterruptedException e) {}
Main Activity: Button Handler<br />
(After Threads Complete)<br />
750<br />
jeudi 26 janvier 12<br />
for(UrlCheckerResult resultHol<strong>de</strong>r: mResultsHol<strong>de</strong>r) {<br />
UrlChecker result = resultHol<strong>de</strong>r.getUrlResult();<br />
if (result == null) {<br />
result =<br />
new UrlChecker(resultHol<strong>de</strong>r.getUrlString(),<br />
HEAD_TIMEOUT);<br />
}<br />
TextView displayedResult = new TextView(this);<br />
displayedResult.setTextColor(chooseColor(result));<br />
displayedResult.setTextSize(mResultTextSize);<br />
displayedResult.setText(result.toString());<br />
displayedResult.setCompoundDrawablesWithIntrinsicBounds<br />
(chooseIcon(result), null, null, null);<br />
displayedResult.setCompoundDrawablePadding<br />
(mResultPaddingSize);<br />
mResultsRegion.addView(displayedResult);<br />
}<br />
}<br />
It would have been be illegal to do this in the background<br />
thread, because it changes the visible UI. Creating the<br />
TextView would have been legal, but adding it to the<br />
vertical LinearLayout insi<strong>de</strong> the ScrollView (as done here)<br />
would have been illegal.
Main Activity:<br />
Runnable Inner Class<br />
751<br />
jeudi 26 janvier 12<br />
private class UrlTester implements Runnable {<br />
private UrlCheckerResult mResultHol<strong>de</strong>r;<br />
}<br />
public UrlTester(UrlCheckerResult resultHol<strong>de</strong>r) {<br />
mResultHol<strong>de</strong>r = resultHol<strong>de</strong>r;<br />
}<br />
public void run() {<br />
UrlChecker result =<br />
new UrlChecker(mResultHol<strong>de</strong>r.getUrlString());<br />
mResultHol<strong>de</strong>r.setUrlResult(result);<br />
}<br />
The run method does not update the UI directly. Instead, it updates a data<br />
structure that will later be read and then used to update the UI (co<strong>de</strong> that<br />
does this was shown on previous sli<strong>de</strong>).<br />
The UrlChecker class does the actual network calls. Since different servers can respond<br />
at different speeds, calling UrlChecker in a background thread can substantially improve<br />
performance.
Main Activity:<br />
Helper Methods<br />
752<br />
jeudi 26 janvier 12<br />
private int chooseColor(UrlChecker urlResult) {<br />
if (urlResult.isGood()) {<br />
return(mGoodUrlColor);<br />
} else if (urlResult.isForwar<strong>de</strong>d()) {<br />
return(mForwar<strong>de</strong>dUrlColor);<br />
} else {<br />
return(mBadUrlColor);<br />
}<br />
}<br />
private Drawable chooseIcon(UrlChecker urlResult) {<br />
if (urlResult.isGood()) {<br />
return(mGoodUrlIcon);<br />
} else if (urlResult.isForwar<strong>de</strong>d()) {<br />
return(mForwar<strong>de</strong>dUrlIcon);<br />
} else {<br />
return(mBadUrlIcon);<br />
}<br />
}<br />
I use different text colors and different icons <strong>de</strong>pending on<br />
whether the URL is good, forwar<strong>de</strong>d, or bad.
Main Helper Classes<br />
• UrlChecker<br />
–Makes a HEAD request and parses status line. If status co<strong>de</strong><br />
is 301 or 302, looks up Location hea<strong>de</strong>r.<br />
• Most of the co<strong>de</strong> shown in earlier lecture on Networking<br />
• UrlCheckerResult<br />
753<br />
jeudi 26 janvier 12<br />
–Stores a URL and the associated UrlChecker result.<br />
• The timeout could be excee<strong>de</strong>d before the results are found, in<br />
which case the UrlChecker is null. In that scenario, we display a<br />
message that shows the URL and says that no result was found<br />
within the allotted time.
Results<br />
754<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Downloading<br />
Web Images<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
Displaying a Network Image<br />
• I<strong>de</strong>a<br />
–The <strong>de</strong>co<strong>de</strong>Stream method of BitmapFactory can take an<br />
InputStream and produce a Bitmap. You can put a Bitmap into<br />
an ImageView<br />
• Approach<br />
756<br />
jeudi 26 janvier 12<br />
–Get an HttpURLConnection (as explained in second<br />
networking lecture)<br />
–Get the input stream with connection.getInputStream()<br />
–Pass the stream to BitmapFactory.<strong>de</strong>co<strong>de</strong>Stream and store<br />
result in Bitmap<br />
–Get a reference to an ImageView and pass new Bitmap to<br />
setImageBitmap
BitmapUtils: Getting a Bitmap<br />
public class BitmapUtils {<br />
public static Bitmap bitmapFromUrl(String urlString)<br />
throws MalformedURLException, IOException {<br />
URL url = new URL(urlString);<br />
HttpURLConnection urlConnection =<br />
(HttpURLConnection)url.openConnection();<br />
InputStream in = urlConnection.getInputStream();<br />
Bitmap bitmapImage = BitmapFactory.<strong>de</strong>co<strong>de</strong>Stream(in);<br />
urlConnection.disconnect();<br />
return(bitmapImage);<br />
}<br />
757<br />
jeudi 26 janvier 12
Making a View for an Image<br />
• I<strong>de</strong>a<br />
–Given an address, try to load a Bitmap from it. If successful,<br />
make an ImageView showing the Bitmap. If unsuccessful,<br />
make a TextView showing information on the error.<br />
• Approach<br />
758<br />
jeudi 26 janvier 12<br />
–Call BitmapUtils.bitmapFromUrl.<br />
• If no Exception, instantiate ImageView and pass Bitmap to<br />
setImageBitmap.<br />
• If Exception, instantiate TextView and store an error message in<br />
it.
BitmapUtils:<br />
Getting a View for an Image<br />
public static View viewForImage(String urlString, Context context) {<br />
Bitmap bitmapImage = null;<br />
String errorMessage = "";<br />
try {<br />
bitmapImage = BitmapUtils.bitmapFromUrl(urlString);<br />
} catch (MalformedURLException mue) {<br />
errorMessage = String.format("Malformed URL %s", urlString);<br />
} catch (IOException ioe) {<br />
errorMessage = String.format("Error downloading image: %s",<br />
ioe.getMessage());<br />
}<br />
if (bitmapImage != null) {<br />
ImageView displayedImage = new ImageView(context);<br />
displayedImage.setImageBitmap(bitmapImage);<br />
displayedImage.setPadding(5, 5, 5, 5);<br />
return(displayedImage);<br />
} else {<br />
TextView displayedMessage = new TextView(context);<br />
displayedMessage.setText(errorMessage);<br />
return(displayedMessage);<br />
}<br />
}<br />
759<br />
jeudi 26 janvier 12
Example:<br />
Unthrea<strong>de</strong>d Image Viewer<br />
• I<strong>de</strong>a<br />
–Let user enter URL of an image to be displayed<br />
–Either show that image, or show error message<br />
• Approach<br />
760<br />
jeudi 26 janvier 12<br />
–Read the address from EditText, pass to<br />
BitmapUtils.viewForImage<br />
–Add resultant View to the layout
Activity<br />
public class SimpleImageDownloa<strong>de</strong>rActivity extends Activity {<br />
private LinearLayout mMainWindow;<br />
private EditText mImageToDownload;<br />
private View mViewForImage;<br />
}<br />
761<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.simple_image_downloa<strong>de</strong>r);<br />
mMainWindow = (LinearLayout)findViewById(R.id.main_window);<br />
mImageToDownload =<br />
(EditText)findViewById(R.id.image_to_download);<br />
}<br />
public void downloadImage(View clickedButton) {<br />
if (mViewForImage != null) {<br />
mMainWindow.removeView(mViewForImage);<br />
}<br />
String imageUrl = mImageToDownload.getText().toString();<br />
mViewForImage = BitmapUtils.viewForImage(imageUrl, this);<br />
mMainWindow.addView(mViewForImage);<br />
}
Results<br />
762<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Updating UI with<br />
View.post<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
View.post<br />
• Scenario<br />
–Total wait time might be large, so you want to show<br />
intermediate results<br />
–You have a lot of normal threading co<strong>de</strong> but you occasionally<br />
need to update UI.<br />
• Approach<br />
764<br />
jeudi 26 janvier 12<br />
–When background thread has result that should affect UI,<br />
create a Runnable and pass to post<br />
public void run() { // Background thread<br />
doStuffButDontUpdateUI();<br />
someView.post(new Runnable() {<br />
public void run() { updateUI(); }});<br />
}
Example: Multithrea<strong>de</strong>d Image<br />
Viewer (Version 1)<br />
• I<strong>de</strong>a<br />
–Let user enter URLs of images to be displayed<br />
–Download and display them insi<strong>de</strong> a scrolling horizontal<br />
LinearLayout<br />
• Approach<br />
765<br />
jeudi 26 janvier 12<br />
–Download images and associate them with ImageView, as<br />
shown in the previous subsection. If there was an error, create<br />
a TextView saying so.<br />
–Create a Runnable that will add the resultant View to the<br />
LinearLayout<br />
–Pass that Runnable to the post method of the LinearLayout
Main Activity: Setup Co<strong>de</strong><br />
public class ImageDownloa<strong>de</strong>r1Activity extends Activity {<br />
protected LinearLayout mResultsRegion;<br />
protected EditText mImagesToDownload;<br />
766<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onCreate(Bundle savedInstanceState) {<br />
super.onCreate(savedInstanceState);<br />
setContentView(R.layout.image_downloa<strong>de</strong>r);<br />
mImagesToDownload =<br />
(EditText)findViewById(R.id.images_to_download);<br />
mResultsRegion =<br />
(LinearLayout)findViewById(R.id.results_region);<br />
}
Main Activity: Button Handler<br />
767<br />
jeudi 26 janvier 12<br />
public void downloadImages(View clickedButton) {<br />
mResultsRegion.removeAllViews();<br />
mResultsRegion.requestLayout();<br />
String[] images =<br />
mImagesToDownload.getText().toString().split("\\s+");<br />
addImages(images);<br />
}<br />
protected void addImages(String[] images) {<br />
ExecutorService taskList =<br />
Executors.newFixedThreadPool(50);<br />
for (String image: images) {<br />
taskList.execute(new ImageDownloa<strong>de</strong>r(image));<br />
}<br />
}<br />
The event handler is split into two methods because the next<br />
example will extend this class and overri<strong>de</strong> addImages, but<br />
will keep the inherited version of downloadImages<br />
unchanged.
Main Activity: Runnable Inner<br />
Class (For Background)<br />
768<br />
private class ImageDownloa<strong>de</strong>r implements Runnable {<br />
private String mImageUrl;<br />
}<br />
jeudi 26 janvier 12<br />
public ImageDownloa<strong>de</strong>r(String imageUrl) {<br />
mImageUrl = imageUrl;<br />
}<br />
public void run() {<br />
View viewToAdd =<br />
BitmapUtils.viewForImage(mImageUrl,<br />
ImageDownloa<strong>de</strong>r1Activity.this);<br />
mResultsRegion.post(new ViewAd<strong>de</strong>r(viewToAdd));<br />
}<br />
This is the task that the ExecutorService executes. It calls viewForImage, a time-consuming<br />
task that loads an image from the network and associates it with an ImageView (or a<br />
TextView if there was an error). The View is then sent to the main UI thread by putting it in a<br />
Runnable and passing the Runnable to the post method of a View that is in the main Activity.
Main Activity: Runnable Inner<br />
Class (For UI Thread)<br />
769<br />
jeudi 26 janvier 12<br />
private class ViewAd<strong>de</strong>r implements Runnable {<br />
private View mViewToAdd;<br />
}<br />
public ViewAd<strong>de</strong>r(View viewToAdd) {<br />
mViewToAdd = viewToAdd;<br />
}<br />
public void run() {<br />
mResultsRegion.addView(mViewToAdd);<br />
}<br />
This changes the UI, so could not have been<br />
done in the background.
Results<br />
770<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Updating UI with<br />
AsyncTask<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
AsyncTask<br />
• Scenario<br />
– Total wait time might be large, so you want to show intermediate<br />
results<br />
– You are <strong>de</strong>signing co<strong>de</strong> from the beginning to divi<strong>de</strong> the work<br />
between GUI and non-GUI co<strong>de</strong><br />
• Approach<br />
– Use AsyncTask with doInBackground & onPostExecute<br />
772<br />
jeudi 26 janvier 12<br />
private class MixedTask extends AsyncTask {<br />
public SomeType doInBackground(…) {<br />
doNonGuiStuff();<br />
return(valueForUiThread);<br />
}<br />
public void onPostExecute(SomeType valueForUiThread) {<br />
doGuiStuffWith(valueForUiThread);<br />
}<br />
}
AsyncTask: Quick Example<br />
• Task itself<br />
private class ImageDownloadTask extends AsyncTask {<br />
public View doInBackground(String... urls) {<br />
return(BitmapUtils.viewForImage(urls[0], MainActivity.this));<br />
}<br />
}<br />
public void onPostExecute(View viewToAdd) {<br />
mResultsRegion.addView(viewToAdd);<br />
}<br />
• Invoking task<br />
String imageAddress = "http://…";<br />
ImageDownloadTask task = new ImageDownloadTask();<br />
task.execute(imageAddress);<br />
773<br />
jeudi 26 janvier 12
AsyncTask Details: Constructor<br />
• Class is genericized with three arguments<br />
– AsyncTask<br />
• Interpretation<br />
– ParamType<br />
• This is the type you pass to execute, which in turn is the type that is<br />
send to doInBackground. Both methods use varargs, so you can send<br />
any number of params.<br />
– ProgressType<br />
• This is the type that you pass to publishProgress, which in turn is<br />
passed to onProgressUpdate (which is called in UI thread). Use Void<br />
if you do not need to display intermediate progress.<br />
– ResultType<br />
• This is the type that you should return from doInBackground, which in<br />
turn is passed to onPostExecute (which is called in UI thread).<br />
774<br />
jeudi 26 janvier 12
AsyncTask Details:<br />
doInBackground<br />
• I<strong>de</strong>a<br />
–This is the co<strong>de</strong> that gets executed in the background. It<br />
cannot update the UI.<br />
–It takes as arguments whatever was passed to execute<br />
–It returns a result that will be later passed to onPostExecute in<br />
the UI thread.<br />
• Co<strong>de</strong><br />
private class SomeTask extends AsyncTask {<br />
public Type2 doInBackground(Type1... params) {<br />
return(doNonUiStuffWith(params));<br />
} ...<br />
}<br />
…<br />
775<br />
jeudi 26 janvier 12<br />
new SomeTask().execute(type1VarA, type1VarB);<br />
The … in the doInBackground <strong>de</strong>claration is actually part<br />
of the Java syntax, indicating varargs.
AsyncTask Details:<br />
doPostExecute<br />
• I<strong>de</strong>a<br />
–This is the co<strong>de</strong> that gets executed by the UI thread. It can<br />
update the UI.<br />
–It takes as an argument whatever was returned by<br />
doInBackground<br />
• Co<strong>de</strong><br />
private class SomeTask extends AsyncTask {<br />
public Type2 doInBackground(Type1... params) {<br />
return(doNonUiStuffWith(params));<br />
}<br />
public void doPostExecute(Type2 result) { doUiStuff(result); }<br />
}<br />
…<br />
new SomeTask().execute(type1VarA, type1VarB);<br />
776<br />
jeudi 26 janvier 12
AsyncTask Details:<br />
Other Methods<br />
• onPreExecute<br />
–Invoked by the UI thread before doInBackground starts<br />
• publishProgress<br />
–Sends an intermediate update value to onProgressUpdate. You<br />
call this from co<strong>de</strong> that is in doInBackground. The type is the<br />
middle value of the class <strong>de</strong>claration.<br />
• onProgressUpdate<br />
–Invoked by the UI thread. Takes as input whatever was passed<br />
to publishProgress.<br />
• Note<br />
777<br />
jeudi 26 janvier 12<br />
–All of these methods can be omitted.
Example: Multithrea<strong>de</strong>d Image<br />
Viewer (Version 2)<br />
• I<strong>de</strong>a<br />
–Let user enter URLs of images to be displayed<br />
–Download and display them insi<strong>de</strong> a scrolling horizontal<br />
LinearLayout<br />
• Approach<br />
778<br />
jeudi 26 janvier 12<br />
–Extend previous example. Make an AsyncTask<br />
–doInBackground<br />
• Download images and associate them with ImageView, as shown<br />
in the previous subsection. If there was an error, create a<br />
TextView saying so. Return that View.<br />
–doPostExecute<br />
• Add the View to the LinearLayout
Activity<br />
public class ImageDownloa<strong>de</strong>r2Activity extends ImageDownloa<strong>de</strong>r1Activity {<br />
@Overri<strong>de</strong><br />
protected void addImages(String[] images) {<br />
for (String image: images) {<br />
ImageDownloadTask task = new ImageDownloadTask();<br />
task.execute(image);<br />
}<br />
}<br />
}<br />
779<br />
private class ImageDownloadTask extends AsyncTask {<br />
@Overri<strong>de</strong><br />
public View doInBackground(String... urls) {<br />
return(BitmapUtils.viewForImage(urls[0],<br />
ImageDownloa<strong>de</strong>r2Activity.this));<br />
}<br />
}<br />
jeudi 26 janvier 12<br />
@Overri<strong>de</strong><br />
public void onPostExecute(View viewToAdd) {<br />
mResultsRegion.addView(viewToAdd);<br />
}
Results<br />
780<br />
jeudi 26 janvier 12
jeudi 26 janvier 12<br />
Wrap-Up<br />
© 2011 Marty Hall<br />
Customized Java EE Training: http://courses.coreservlets.com/<br />
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android.<br />
Developed and taught by well-known author and <strong>de</strong>veloper. At public venues or onsite at your location.
More Reading<br />
• JavaDoc<br />
–AsyncTask<br />
• http://<strong>de</strong>veloper.android.com/reference/android/os/AsyncTask.html<br />
• Tutorial: Processes and Threads<br />
–http://<strong>de</strong>veloper.android.com/gui<strong>de</strong>/topics/fundamentals/<br />
processes-and-threads.html<br />
• Chapters<br />
782<br />
jeudi 26 janvier 12<br />
–Threads, Services, Receivers, and Alerts<br />
• From The Android Developer’s Cookbook by Steele & To<br />
–Dealing with Threads<br />
• From The Busy Co<strong>de</strong>r’s Gui<strong>de</strong> to Android Development<br />
by Mark Murphy (http://commonsware.com/Android/)
Summary<br />
• Update UI after all threads done<br />
–Use taskList.awaitTermination<br />
• Update UI incrementally with post<br />
–Main thread does non-GUI stuff. Sends values for UI thread<br />
via someView.post(someRunnable)<br />
• Update UI incrementally with AsyncTask<br />
–doInBackground<br />
• Does non-GUI stuff. Returns value for UI thread.<br />
–doPostExecute<br />
• Does GUI stuff. Uses value from doInBackground<br />
• Loading images from network<br />
783<br />
jeudi 26 janvier 12<br />
–Use HttpURLConnection & BitmapFactory.<strong>de</strong>co<strong>de</strong>Stream