TD Android - UV TL53 UTBM
Transcription
TD Android - UV TL53 UTBM
Démarrage du PC: - Allumer le pc et mettre rapidement le DVD - Taper F12 ( écran noir au début avant XP ) pour démarrer sur le DVD et pas le disque dur - Choisir la première ligne = Live ( pas une autre !!! ) On va simuler un ordinateur en utilisant µP et RAM du PC ( mais pas son disque dur ) Remarque: Il accède à Internet si on utilise le proxy: http://www.utbm.fr/proxy.pac - Ubuntu 10 démarre: login: uv, mdp: utbm S'il y a des messages d'erreurs, faites supprimer. => On a un PC sous Linux avec les outils pour développer des applications pour Android sans rien installer sur le PC réel. TD Android v2.0 I) Savoir utiliser la documentation Android de Google: Application au cycle de vie ( Lifecycle ) Android fournit beaucoup d'informations aux développeurs. Soit sur le web ( en parrticulier recherche google avec les mots clés "Android Developper" ) Soit avec les documents Google installés avec le SDK Android ( Software Developpment Kit ). En installant le SDK Android, on a aussi installé la documentation Google. - Cliquer sur l'icône du Bureau renvoyant aux documents Google: raccourci "docs Android". - En haut à droite, mettre "Lifecycle" , choisir le lien qui commence par "Activity" => En descendant, on a le dessin du cycle de vie ( Lifecycle ) de l'application c'est à dire que quand l'utilisateur lance son application Android, cela passe dans le programme par la méthode "onCreate" puis "onStart" puis .... ( En JAVA, une méthode est une fonction faisant partie d'une classe ). II) Savoir créer un projet Android 1) Lancer le logiciel Eclipse, clic sur icone android => s'il y a un message d'erreur, aller dans window/preference.sdk location, vérifier qu'il y a un chemin ( /usr/local/src/android-sdk... ), OK 2) Faire un projet dans Eclipse: - file / new / other / android / android project, next * mettre un nom de projet : intro * mettre la cible ( Build target ) qui correspond à l'étape précédente AVD = cocher devant Android 2.2 par exemple ( à la création de l'AVD, des messages indiquent la version Android correspondante ) * mettre un nom d'application: Essai * mettre un nom de paquet Java: Package Name com.exemple.UV_UTBM ( pas de - ) * cocher "create activity" si ce n'est fait, mettre le nom de projet Finish * Min SDK Version: Mettre la valeur de la colonne "API Level" de la cible choisie ( voir tableau Build Target, si on a mis Cible Android 2.2, alors on met API Level 8 par exemple ) Remarque: Pour modifier à postériori le nom de l'application "application name": choisir strings.xml dans l'arborescence du projet, puis dans la fenêtre du milieu, prendre l'onglet en bas "strings.xml" ( pas ressources ). On a le code de base du projet. Il y a 3 éléments importants AndroidManifest.xml src nom.java nom.java Autorisations Fichiers sources du projet 1/12 res drawable Répertoire des icône, images, fond écran layout Affichages: main.xml = organisation de l'interface utilisateur autre xml si on a plusieurs fenêtres values Définition de constantes: strings.xml = chaines de caractères integer.xml, ... Sources architecture: http://www.ibm.com/developerworks/opensource/library/os-android-devel/ Le code de base du fichier java appelle l'affichage défini dans main.xml ( setContentView(R.layout.main ). Le fichier res/layout/main.xml fait l'affichage de la variable texte ( Textview ) hello dans le fichier ressources strings.xml - Modifier la chaine qui doit s'afficher ( Dans le projet > res > values > strings.xml ) => Clic en bas sur strings.xml pour voir le code brut, trouver la ligne de variable hello ( en bleu ) => Modifier sa valeur avec un texte de votre choix = partie en noir ( ne pas mettre d'accent dans votre texte ). - Sauvegarder ( icône disquette ) 3) Créer un téléphone virtuel ou raccorder un téléphone réel Téléphone virtuel = AVD ( Android Sous Eclipse: Accès à "AVD Manager" par l'icône ligne AVD, Virtual Device ) Clic sur "New...", name = nom au choix, Target = version Android: Mettre une ligne "Android x.x – API Level y" ( au moins la version du projet, donc Android 2.2 – API Level 8 ) Size = Mémoire: Ne pas mettre trop de mémoire sinon cela plante => 64 Mib, pas 16000 Mib ). Create AVD, fermer la fenêtre. Remarque: On pourrait aussi le faire en ligne de commande sous tools en root: android create avd --target 8 --name rtphone ( target = version d'android, rtphone = nom téléphone virtuel ) Téléphone réel Pour communiquer avec un téléphone réel, on utilise l'ADB (Android Debug Bridge ). Pour cela il faut: a) Dans le programme, fichier Manifeste AndroidManifest.xml: - Déclarer l’application comme "debuggable" dans le manifeste Android: Dans AndroidManifest.xml, dans la partie <application>, ajouter avant le > de fermeture android:debuggable="true" b) Sur l'appareil Android réel recevant le programme: - Activer « USB debugging » sur l’appareil qui reçoit l’application: Menu / Applications / Development / USB Debugging - Redémarrer sinon ensuite on verra le téléphone toujours offline c) Sur le PC de développement où on développe l'application avec le SDK: - Sous windows: Installer les drivers ADB spécifiques au matériel réel - Sous Linux: + Passer en root ( dans un terminal taper "sudo su", mot de passe utbm ) + Créer un fichier /etc/udev/rules.d/51-android.rules + Ajouter dans ce fichier la ligne pour les versions Ubuntu après la 6 ( Dapper ) SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666" La valeur de SYSFS{idVendor} dépend du constructeur de l’appareil : Samsung 04e8 Archos 0e79 HTC = 0bb4 Huawei 12d1 LG 1004 Motorola 22b8 Sony Ericsson 0fce Google 18d1 Autre = http://www.linux-usb.org/usb.ids + Vérifier le code en faisant lsusb dans un terminal, code = 1ère partie après ID + Changer les permissions : chmod a+rx /etc/udev/rules.d/51-android.rules + Redémarrer ( au moins ./adb kill-server ( faire "locate adb" pour trouver le répertoire puis ./adb start-server qui démarre un pid ) + Vérifier la connexion: ./adb devices * Si on a connexion, on verra apparaître une liste qui inclut l’appareil. * S’il y a un problème de déclaration ( valeur SYSFS{idVendor} par exemple ), on a « ?????????? no permissions » => Refaire ./adb kill-server puis ./adb start-server * S'il est marqué offline, alors qu'allumé, vérifier que " USB Debugging" a été activé sur le téléphone et qu'il a été redémarré. 2/12 4) Lancer l'application: Sous Eclipse faire run ou debug ( icône triangle ), Android Application, être patient.... Choisir l’appareil dans la liste proposée s'il y en a plusieurs ( ceux non offline ). Remarque: Pour seulement installer l’application sur l’appareil, on utilise "adb install <chemin vers apk>". En cas d'incohérence de nom entre projet, activité, on aura une erreur avant compilation ou après avec message de fermeture ( Exemple: package = calculatrice, appli = Calculatrice ) III) Savoir ce que fait le programme : outils de Debug Lors du développement d'une application, on aura sûrement besoin de faire du débuggage. On va utiliser les outils disponibles pour étudier l'évolution de l'application entre les différentes méthodes: Outils de débuggage = Message de Log. On a le choix entre différents contenus de message. Log.v Log.d Verbose Debug Log.i Info Log.w Warn Log.e Error Verbose est le plus détaillé mais ne doit pas être compilé dans une application sauf en phase de développement, Error est le moins détaillé. La syntaxe est pour l'affichage du texte "index" puis de la valeur de variable i: Log.e(TAG, "index=" + i); Attention: Ces messages ralentissent l'application et consomment des ressources mémoires ( Log.v surtout ). - Modifier votre projet en ajoutant au programme JAVA ( descendre l'arborescence de votre projet > src > ... ), - import android.util.Log; dans les import - Ajouter une chaine de caractères identifiant les messages en début de la classe ( ligne après class{ ) private static final String TAG= “Test Etats”; - Ajouter une ligne à la fin de la méthode onCreate: Log.e(TAG,"passage onCreate"); - Ajouter les méthodes non présentes trouvée dans la doc pour le cycle de vie en y incluant un message de Log: exemple onStart: @Override protected void onStart(){ super.onStart(); Log.e(TAG, "passage onStart"); } Utilisation Pour avoir des informations sur une erreur: Cliquer sur Debug , ( pour revenir on cliquera sur Java. ). S'il n'y a pas d'affichage Logcat, aller dans Window/ Show view/ LogCat. - Faire Run et observer par quelles étapes on passe. Remarques: - Si on ne voit pas de message: - Aller dans la perspective DDMS au lancement de l'application, - Cliquer juste sur le nom d'un processus actif ( Onglet Devices après qu'il passe Online ). - Si on veut filtrer les messages, cliquer sur v, d, ,i, w ou e. ( on verra tous les messages de hiérarchie inférieure ) 3/12 - "Jouer" avec l'application en appuyant sur la touche HOME, en revenant à l'application,... ( CTRL+F11 et CTRL+F12 change l'orientation de l'émulateur, http://developer.android.com/guide/developing/tools/emulator.html ) => On doit voir les différents états du cycle de vie se succéder. - Fermer l'application sur le téléphone ( pour le téléphone virtuel, ne pas fermer l'émulateur, cela prendra moins de temps ). IV) Savoir créer une interface graphique Le programme java appelle un fichier xml et affiche son contenu. ( par défaut main.xml dans res/layout ). On va créer notre affichage, pour cela on utilise l'outil DroidDraw qui va générer le code xml. Utilisation de DroidDraw - Cliquer sur l'icône du bureau Droiddraw, clic sur Droiddraw.sh, lancer. On a sur la droite les éléments graphiques que l'on peut incorporer dans l'affichage à gauche. - Placer une case pour le texte ( EditText ) et en-dessous 2 boutons ( Button ) = Faire glissser de la partie droite à gauche. - Cliquer sur Generate en bas à droite. - Copier/Coller le code XML: CTRL+A, CTRL+C dans Droiddraw ( partie Output ), CTRL+V dans le fichier main.xml de Eclipse ( votre projet > layout > main.xml ) On retrouve 3 balises xml ( chapitre <nom> à </nom> ): EditText et Button. Chacune a son identifiant ( ligne android:id="@id/nom" ) - Modifier la balise EditText en ajoutant la ligne android:editable="false" => La case de texte ne sera utilisable qu'en sortie ( affichage ), pas en entrée ( entrée de texte = getText ) - Modifier la balise EditText à sa ligne android:text=".." et mettre "Texte de départ" - Enregistrer et lancer l'application et vérifier que l'on retrouve l'organisation définie dans DroidDraw. Ajout d'icône On veut modifier l'icône associée à notre application dans le menu des applications. Faire un fichier icon.png contenant l'image à associer comme icône. ( aller dans le répertoire photos sur le bureau ) Vérifier que dans le fichier AndroidManifest.xml on a: <application android:icon="@drawable/icon" android:label="@string/app_name"> Dans les anciennes versions, il manque le début, par défaut on n'a que <application android:label="@string/app_name"> - Ouvrir le répertoire de travail: Raccourcis > Dossier personnel > workspace - Aller dans votre projet, res, parties drawables - Mettre dans les répertoires drawable ( hdpi pour affichage haute densité, ldpi low, mdpi medium ) le fichier image représentant l'icône: icon.png 4/12 Remarque: Pour des raisons de temps on a fait un affichage simple avec une seule taille d'icône ( normalement valable pour Android avant 1.6 = il n'y avait qu'un affichage = Un répertoire drawable ). Pour la version 1.6 et suivante: Multiscreeen ( hdpi, mdpi, ldpi ) => 3 affichages selon le terminal, 3 tailles d'icônes. On reprend le principe précédent mais avec plusieurs cibles: ldpi: Low icône 36 x 36 pixels mdpi: Medium icône 48 x 48 pixels hdpi: High icône 72 x 72 xhdpi: Extra High après version 2.2 Définir quel type d'écran peut accueillir l'application avec les variables dans la partie supportsscreens du manifeste: android:smallScreens, android:normalScreens, android:largeScreens, android:anyDensity Mettre l'image de l'icône dans les répertoires correspondants de res/drawable Ajout de fond d'écran a) Changer la couleur du fond - Ajouter dans main.xml à la définition du layout android:background="#000044" ( 000044 = code couleur ) - Fermer l'émulateur et relancer: On doit avoir une autre couleur de fond. Puis aller dans le menu pour voir l'icône. b) Image en fond - Placer l'image background.9.png dans les sous-répertoires ( en multiscreen ) de res/drawable. Modifier dans main.xml à la définition du layout android:background="@drawable/background" Remarque: Pour construire son image, soit on met une image 480x640, soit on utilise l'utilitaire draw9patch ( dans tools du répertoire SDK ). Cela supprime 1 pixel au bord et permet de définir les zones d’image qui vont s'étirer si on change d'écran ( strech ). - Sauvegarder, ré-installer l'application pour vérifier les modifications. - Placer l’image fondecran.png qui fait 480x640 dans les répertoires drawable, modifier la ligne du main.xml android :background="@drawable/fondecran" Sources: Type d'écran: 9-patch: http://developer.android.com/guide/practices/screens_support.html http://android.cyrilmottier.com/?p=127 V) Savoir associer aux éléments graphiques des écouteurs d'événements On va utiliser les 2 boutons pour que le clic sur le premier affiche un message dans l'EditText, le clic sur le second affiche un autre message. Vibreur après appui de bouton - Trouver la ligne de définition de l'identité du premier bouton: Dans main.xml, ligne android:id="@+id/identité" Définir comme identité du bouton "@+id/Bouton_Vibreur". Mettre android.text="Vibreur". - Ajouter en début de programme JAVA: import android.widget.Button; import android.widget.Toast; import android.view.View; import android.view.View.OnClickListener; - Ajouter à la fin du programme JAVA dans onCreate, juste après setContentView(R.layout.main); final Button Instbouton = (Button) findViewById(R.id.Bouton_Vibreur); Instbouton.setOnClickListener(new OnClickListener() { public void onClick(View v) { Toast.makeText(Nomprojet.this, "Vibration", Toast.LENGTH_SHORT).show(); // action à réaliser au clic /* Nomprojet est défini au début = nom de l'activité ( voir public class Nomprojet extends Activity ) */ } }); /* attention: crochet puis parenthèse */ => On a instancié un bouton = InstBouton associé au widget Bouton_Vibreur => On a défini un écouteur d'événements sur notre élément de Layout Bouton_Vibreur. Instbouton.setOnClickListener => En cas de clic ( Onclick ), on appelle le traitement à réaliser, ici afficher un message de durée Toast.LENGTH.SHORT. - Vérifier que le clic fonctionne = Lancer, l'application, cliquer => Affichage du message. 5/12 On a fait une action simple ( affichage message) avec le clic. On veut compliquer l'action associée: Faire vibrer le téléphone. - Autoriser la mise en vibration: Dans AndroidManifest.xml, avant la ligne <application..., ajouter la ligne <uses-permission android:name="android.permission.VIBRATE"> </uses-permission> Tout écrire même s'il y a d'autres lignes <uses-permission ...> - En début de programme JAVA: import android.os.Vibrator; - A l'intérieur de la classe principale ( en parallèle de onCreate ), définir une méthode dans le fichier JAVA qui va afficher le message, faire vibrer et modifier le texte de la boite texte du dessus. public void Action_1(View v) { Toast.makeText(intro.this, "Vibration", Toast.LENGTH_SHORT).show(); // Instanciation de Vibrator pour le context courant = intro = nom de la classe du "extends Activity" Vibrator vibreur = (Vibrator) getSystemService(intro.VIBRATOR_SERVICE); vibreur.vibrate(2500); // Vibration de 2500 milliseconds } /* fin Action_1 */ - Enlever la ligne Toast.makeText(Nomprojet.this, "Vibration", ... dans onClick et appeler à la place: Action_1(v); - Vérifier que le clic fonctionne = Affichage du message et sur un téléphone réel il doit aussi vibrer. Gestion de plusieurs clics On pourrait refaire la même gestion que pour un bouton mais cela devient lourd si on a plusieurs boutons. On va à la place réécrire setOnClickListener. - Trouver la ligne de définition de l'identité du second bouton ( dans main.xml, ligne android:id="@+id/identité" ) Définir comme id du bouton "@+id/Bouton_Texte". Mettre android.text="Texte" - Ajouter dans le onCreate final Button Instbouton2 = (Button) findViewById(R.id.Bouton_Texte); - Supprimer dans onCreate Instbouton.setOnClickListener(new OnClickListener() { public void onClick(View v) { Toast.makeText(Nomprojet.this, "Vibration", Toast.LENGTH_SHORT).show(); // action à réaliser au clic /* Nomprojet est défini au début = nom de l'activité ( voir public class Nomprojet extends Activity ) */ } }); /* attention: crochet puis parenthèse */ - Ajouter à la définition de la classe ( ligne public class avant le { de début ): "implements OnClickListener" - Ajouter en fin de onCreate les définitions des écouteurs sans les guillemets. Instbouton.setOnClickListener(this); Instbouton2.setOnClickListener(this); - Ecrire la fonction de traitement des clics dans la class en parallèle des autres méthodes: public void onClick(View v) { switch(v.getId() ) { case R.id.Bouton_Vibreur: Action_1(v); break; case R.id.Bouton_Texte: Action_2(v); break; } } - Ajouter en début de programme JAVA: import android.widget.EditText; - Ajouter la méthode Action_2 dans la class en parallèle des autres méthodes:: public void Action_2(View v) { EditText macasetexte = (EditText)findViewById(R.id.widget27); // où widget27 est le nom du EditText dans main.xml } Toast.makeText(Nomprojet.this, "Texte", Toast.LENGTH_SHORT).show(); macasetexte.setText("clic bouton texte"); - Tester le clic des 2 boutons. 6/12 VI) Savoir utiliser les modules internes: GPS Le GPS utilise les classes prédéfinies dans le SDK LocationManager Accès aux services de localisation LocationListener Réception des notifications venant de LocationManager quand la position change Location Position géographique Address Adresse = ensemble de chaines décrivant la position A cela on peut ajouter la classe "Geocoder" qui donne accès au service de géolocalisation de Google. - Créer un nouveau projet: file / new / other / android / android project, next Mettre le nom de projet monGPS pour utiliser le code JAVA suivant, nom de package fr.monGPS.UV_UTBM ( pour cohérence du programme java avec AndroidManifest ) - Modifier AndroidManifest.xml pour avoir les permissions d'utilisation du GPS par puce GPS. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission> Pour le GPS par réseau téléphonique, il faut aussi ajouter: <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission> <uses-permission android:name="android.permission.INTERNET"></uses-permission> - Lancer Droiddraw ( icône sur bureau puis clic droiddraw.sh puis lancer ). => On prépare le graphisme de l'appli. - Cliquer sur Textview dans l'onglet Widgets. Faire glisser dans la fenêtre de l'application. - Cliquer sur l'onglet Properties. Mettre les valeurs suivantes dans les cases: Id Text @+id/TextView01 Latitude Id Text @+id/latitude 0.0 Id Text @+id/TextView02 Longitude Id Text @+id/longitude 0.0 Id Text @+id/lecture_position GPS - Cliquer sur le bouton "Apply" en dessous - Cliquer sur EditText dans l'onglet Widgets. Faire glisser dans la fenêtre de l'application à côté de la case précedente. - Cliquer sur l'onglet Properties. Mettre les valeurs suivantes dans les cases: - Cliquer sur le bouton "Apply" en dessous - Cliquer sur Textview dans l'onglet Widgets. Faire glisser dans la fenêtre de l'application en dessous des 2 autres. - Cliquer sur l'onglet Properties. Mettre les valeurs suivantes dans les cases: - Cliquer sur le bouton "Apply" en dessous - Cliquer sur EditText dans l'onglet Widgets. Faire glisser dans la fenêtre de l'application à côté de la case précedente. - Cliquer sur l'onglet Properties. Mettre les valeurs suivantes dans les cases: - Cliquer sur le bouton "Apply" en dessous - Cliquer sur Button dans l'onglet Widgets. Faire glisser dans la fenêtre de l'application en dessous des 2 autres. - Cliquer sur l'onglet Properties. Mettre les valeurs suivantes dans les cases: - Cliquer sur le bouton "Apply" en dessous On obtient un écran du style: Latitude 0.0 Longitude 0.0 GPS - Cliquer sur le bouton "Generate" en bas de fenêtre DroidDraw. Faire un copier du texte généré ( cliquer dans la fenêtre puis CTRL+A puis CTRL+C ). - Aller dans Eclipse sur votre projet / res / layout / main.xml, cliquer sur main.xml. Cliquer sur main.xml en bas de fenêtre. - Enlever le texte présent et mettre à la place le code généré avec DroidDraw en le collant: CTRL+V. - Enregistrer. - Créer le programme JAVA ( étant donné le temps limité on fera un copier/coller du tableau suivant ). 7/12 package fr.monGPS.UV_UTBM; programme JAVA pour GPS import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; import android.widget.Toast; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; public class monGPS extends Activity implements OnClickListener , LocationListener { private LocationManager lmg; private Location location; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //Utilisation du service de localisation lmg = (LocationManager) getSystemService(Context.LOCATION_SERVICE); //Affection d'écouteur d'évènement au bouton findViewById(R.id.lecture_position).setOnClickListener(this); } // Fin onCreate //Méthode utilisée au clic sur un bouton public void onClick(View v) { // le service de localisation notifie tout changement de position toutes les 30s = 30000 ms. // paramètre this = notre classe implémente LocationListener et recevra les notifications. lmg.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30000, 0, this); } // Fin onClick public void onLocationChanged(Location location) { this.location = location; // on sauvegarde la position AffichePosition (); // on l'affiche lmg.removeUpdates(this); // indique au service que l'on ne veut plus de mise à jour // seul le clic permet de relancer la lecture } public void onProviderDisabled(String provider) { //source est désactivée Toast.makeText(monGPS.this,"source désactivée",Toast.LENGTH_SHORT).show(); // => affiche un Toast lmg.removeUpdates(this); // on spécifie au service que l'on ne veut plus de mise à jour } public void onProviderEnabled(String provider) { // La source a été activée, vide par simplification } public void onStatusChanged(String provider, int status, Bundle extras) { // Le statut de la source a changé, vide par simplification } private void AffichePosition() { // affichage des informations de position à l'écran ((TextView)findViewById(R.id.latitude)).setText(String.valueOf(location.getLatitude())); ((TextView)findViewById(R.id.longitude)).setText(String.valueOf(location.getLongitude())); } // Affichage après lecture position } Explication: => Au démarrage onCreate fait l'affichage de main.xml, crée un service LocationManager, crée un écouteur de bouton. => S'il y a un clic onClick active la lecture du GPS pour notre bouton => S'il y a un changement de position = onLocationChanged, on lance l'affichage = Appel AffichePosition. 8/12 Test du programme sur téléphone réel: Sortir du batiment ( signaux GPS pas reçus à l'intérieur ): Clic sur le bouton GPS, le GPS s'active, attendre. Test du programme sur émultateur = téléphone virtuel: Pour modifier la position GPS de l'émulateur, on peut utiliser 2 méthodes:: Par telnet Par DDMS - Ouvrir la perspective DDMS dans eclipse ( bouton en * Se connecter en telnet à l'émulateur lancé: haut à droite ou window/perspective/Other.../DDMS ) Ouvrir un terminal et taper telnet localhost 5554 - Partie "Emulator Control" sur la gauche: * help ou help gps Descendre à "Location Control" * Pour définir une position gps - Entrer Longitude et Latitude 47,494813 6,803015 geo fix 47.494813 6.803015 - Cliquer sur Send. ( syntaxe: gps fix longitude latitude altitude, ( clic avant sur l'émulateur dans devices au-dessus si nécessaire ) l'altitude est optionnelle ) Clic sur le bouton GPS, on doit voir les coordonnées entrées dans l'émulateur. Remarque: En telnet, on a aussi la simulation de messages NMEA: Pour définir une trame NMEA * geo nmea $GPGGA,001431.092,0118.2653,N,10351.1359,E,0,00,,-19.6,M,4.1,M,,0000*5B ATTENTION: Cela marche mal sur un PC français car l'altitude n'est pas traitée et la virgule est traduite en point. => Incompréhension des valeurs et affichage "bancal". => Utiliser l'outil suivant DDMS. Remarque DDMS: DDMS ( Dalvik Debug Monitor Server ) est dans le répertoire Tools du SDK. On a ajouté à eclipse un onglet via: window/perspective/Other.../DDMS http://developer.android.com/guide/developing/debugging/ddms.html VII) Savoir éviter de bloquer le terminal Android gère plusieurs taches à la fois ( exemple: affichage, réception de sms, communication bluetooth, mises à jour en tache de fond,... ). Il faut éviter qu'une application bloque les autres donc on ne peut faire un traitement trop long, Android fermera l'application. Mise en évidence du problème On va utiliser un chrono dans l'UI principale et faire en même un traitement long. - Créer un nouveau projet - Créer l'interface avec 2 boutons. - Ajouter dans la définition du bouton 1 dans main.xml android:text="Chrono" android:onClick="DemarreChrono" - Ajouter dans la définition du bouton 2 dans main.xml android:text="Traitement" android:onClick="Traitement" - Ajouter le chronomètre au main.xml ( entre les balises de layout comme les boutons ou le EditText ) <Chronometer android:id="@+id/chrono" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textSize="30dip" /> - Ajouter les import en début de programme java import android.os.SystemClock; import android.util.Log; import android.view.View; import android.widget.Chronometer; import android.widget.Chronometer.OnChronometerTickListener; import android.widget.Toast; - Ajouter la définition en début de class avant onCreate: private static final String TAG = "test"; 9/12 - Ajouter la méthode Traitement dans le fichier java qui simule un téléchargement de 10s public void Traitement(View target) { // il faut un view qui sert pas ! sinon erreur avec onclic du main.xml try { Log.e(TAG, "début traitement"); Thread.sleep(10000); // blocage 10 s Log.e(TAG, "fin traitement"); Toast toast = Toast.makeText(getApplicationContext(), "fin traitement", Toast.LENGTH_SHORT); toast.show(); } catch(Exception e) { Log.e(TAG, "problème"); } } - Ajouter la gestion du chronomètre - à la fin de la ligne définissant la classe - dans onCreate: implements OnChronometerTickListener { ((Chronometer)findViewById(R.id.chrono)).setOnChronometerTickListener(this); - ajouter la méthode de gestion du chrono public void onChronometerTick(Chronometer chr) { long TpsEcoule = SystemClock.elapsedRealtime() - chr.getBase(); int min = (int)(TpsEcoule/60000); int sec = (int) ((TpsEcoule/1000) % 60); String time = min<10? "0" + min : String.valueOf(min); time += ":"; time += sec<10? "0" + sec : String.valueOf(sec); ((Chronometer)findViewById(R.id.chrono)).setText(time); } - ajouter a méthode de démarrage du chrono public void DemarreChrono(View target) { ((Chronometer) findViewById(R.id.chrono)).setBase(SystemClock.elapsedRealtime()); ((Chronometer) findViewById(R.id.chrono)).start(); } - Lancer l'application, démarrer le chrono en cliquant sur bouton dédié à cela. - Après 5s, démarrer le traitement en cliquant sur son bouton - Que se passe-t-il avec le temps affiché ? Que se passe-t-il si on appuie à nouveau sur le bouton du chrono ? Solution: Nouveau Thread On va créer un nouveau Thread pour faire ce traitement => Le système gère les accès aux 2 traitements. - Modifer Traitement dans le fichier: On crée un Thread "monThread" en tâche de fond ( background ) qui appelle TraitementEnFond public void Traitement(View target) { // il faut un view qui sert pas ! sinon erreur avec onclic du main.xml // Déplacement des traitements dans un Thread enfant. Thread monThread = new Thread(null, TraitementEnFond,"Background"); monThread.start(); } - Ajouter TraitementEnFond : On démarre ( run d'un Runnable ) la méthode monThreadTraitements private Runnable TraitementEnFond = new Runnable() { public void run() { monThreadTraitements(); // appel de la méthode des traitements } }; 10/12 - Ajouter monThreadTraitements: Réalisation des traitements private void monThreadTraitements() { // Méthode qui fait les traitements en tâche de fond. try { Log.e(TAG, "début traitement"); Thread.sleep(10000); // blocage 10 s Log.e(TAG, "fin traitement"); runOnUiThread(new Runnable() { public void run() { Toast toast = Toast.makeText(getApplicationContext(), "fin traitement", Toast.LENGTH_SHORT); toast.show(); } }); } catch(Exception e) { Log.e(TAG, "problème"); } } Remarque: On n'est plus dans l'UI principale qui gère l'affichage mais que l'on est dans monThread => Le Toast ne fonctionne plus, il faut le faire modifier l'UI principale ( affichage. => D'où la présence de runOnUiThread Remarque: Ici il n'y a pas d'échange entre les Threads. Si on doit en faire, il faut utiliser des Handlers pour échanger des Messages. - Recommencer les tests précédents pour voir que le chrono n'est plus bloqué même s'il y a traitement. - Observer les threads avec DDMS ( se placer sur votre processus dans Devices, cliquer sur ) A la fin: Sur le téléphone réel, penser à supprimer une application Sur le téléphone: - Paramètres / Applications / Gérer les applications / - Sélectionnez l'application à désinstaller : - Désinstaller / OK 11/12 Annexe Cycle de vie de l'application 12/12