Commander un Arduino avec une tablette Android

- Etude de cas -


précédentsommairesuivant

XI. Le client natif Android du projet Domotique

Nous abordons maintenant l'écriture du client Android.

A lire

  • le document [ref2] jusqu'à l'exemple 2 inclus. Nous allons suivre cet exemple pour écrire notre client Android. Le modèle AVAT doit être compris pour la suite du TP.

XI-A. Les du client

Le client Android permet de gérer les Arduinos à distance. Il présente à l'utilisateur les écrans suivants :

L'onglet [CONFIG] permet de se connecter au serveur et de récupérer la liste des Arduinos connectés :

Image non disponible

L'onglet [PINWRITE] permet d'écrire une valeur sur une pin d'un Arduino :

Image non disponible

L'onglet [PINREAD] permet de lire la valeur d'une pin d'un Arduino :

Image non disponible

L'onglet [BLINK] permet de faire clignoter une led d'un Arduino :

Image non disponible

L'onglet [COMMAND] permet d'envoyer une commande JSON à un Arduino :

Image non disponible

XI-B. L'architecture du client

L'architecture du client Android sera la suivante :

Image non disponible
  • la couche [DAO] communique avec le serveur REST. C'est un client REST implémenté par Spring-Android ;
  • la couche [métier] reprend l'interface de la couche [métier] du serveur ;

Les versions actuelles d'Android exigent que les connexions réseau soient faites dans un autre thread que celui qui gère les interfaces visuelles. C'est ce qui explique la présence du bloc [4]. Les méthodes de la couche [métier] sont exécutées au sein d'un thread différent de celui de l'UI (User Interface). Lorsqu'on fait exécuter une méthode de la couche[métier] dans un thread, on peut attendre ou non la réponse de la méthode. Dans le premier cas, synchrone, on bloque l'UI en attendant la réponse de la tâche. Dans le second cas, asynchrone, l'UI reste disponible pour l'utilisateur qui peut lancer d'autres actions. Ici, on a choisi la solution asynchrone pour deux raisons :

  • le client Android doit pouvoir commander plusieurs Arduinos simultanément. Par exemple, on veut pouvoir faire clignoter une led placée sur deux Arduinos, en même temps et non pas l'une après l'autre. On ne peut donc pas attendre la fin de la première tâche pour commencer la seconde ;
  • les connexions réseau peuvent être longues ou ne pas aboutir. Pour cette raison, on veut donner à l'utilisateur la possibilité d'interrompre une action qu'il a lancée. Pour cela, l'UI ne doit pas être bloquée.

Les vues [2] sont les interfaces visuelles présentées à l'utilisateur. Sur une tablette, elles ressemblent à ceci :

Image non disponible

A partir de cette vue, l'utilisateur lance une action avec le bouton [Exécuter].

Image non disponible

Le bloc [3] regroupe les actions exécutées par les vues. La vue ne fait que saisir des données et contrôler leur validité. On part du principe qu'elle ne sait pas à quoi elles vont servir. Elle sait simplement à quelle action elle doit transmettre les données saisies. L'action lancera les tâches asynchrones nécessaires, mettra en forme leurs résultats et rendra à la vue un modèle pour que celle-ci se mette à jour. La vue n'est pas bloquée par l'action, afin de donner à l'utilisateur la possibilité de l'interrompre.

Les activités [1] sont le coeur d'une application Android. Ici on n'en a qu'une et elle ne fait quasiment rien si ce n'est d'assurer les changements de vues. On appellera ce modèle, AVAT (Activité - Vues - Actions - Tâches). Il peut être allégé de la façon suivante :

Image non disponible

Dans le modèle AVAT, la vue est complètement ignorante de l'utilisation faite des données qu'elle a saisies. Dans le modèle AVT ci-dessus (Activité - Vues - Tâches), la logique de l'action est transférée dans la vue. On trouve donc un peu de logique dans la vue. Celle-ci doit organiser les appels des tâches asynchrones elle-même. Cette logique est forcément faible. Si elle était importante, elle serait normalement transférée dans la couche [métier]. Ce modèle AVT est suffisant dans tous les cas.

XI-C. Les projets Eclipse du client

Image non disponible

Les projets Android suivent l'architecture ci-dessus :

Image non disponible

En [1] les cinq projets Eclipse du client Android :

  • [domotique-entities] : projet déjà utilisé pour le serveur. Rassemble les entités échangées entre le client Android et le serveur REST ;
  • [android-dao] : la couche [DAO] du client Android ;
  • [android-metier] : la couche [métier] du client Android ;
  • [android-ui], [android-avat] : la couche [présentation] du client Android qui s'appuie sur le modèle AVAT décrit dans [ref2].

En [2] les packages de la couche AVAT du client Android :

  • [istia.st.domotique.android.activity] : rassemble ce qui a trait au 1er A de AVAT, l'activité ;
  • [istia.st.domotique.android.vues] : rassemble ce qui a trait au V de AVAT, les vues ;
  • [istia.st.domotique.android.actions] : rassemble ce qui a trait au 2ième A de AVAT, les actions ;
  • [istia.st.domotique.android.tasks] : rassemble ce qui a trait au T de AVAT, les tâches ;

XI-D. Le manifeste de l'application

Image non disponible

Le fichier [AndroidManifest.xml] configure l'application. C'est le suivant :

 
CacherSélectionnez
  • ligne 3 : le paquetage du projet Android. Un certain nombre de classes seront automatiquement générées dans ce paquetage [3] ;
  • ligne 8 : la version minimale d'Android pouvant exécuter l'application. Ici la version 14, une version récente ;
  • ligne 9 : la version maximale d'Android. Mettre la dernière version de cet OS ;
  • ligne 11 : ligne à mettre si l'application ouvre des connexions Internet. C'est le cas ici. Si on l'oublie, on a une exception parfois peu compréhensible lors des ouvertures de connexion réseau ;
  • ligne 15 : l'icône [2] de l'application ;
  • ligne 16 : le libellé de l'aplication. Il se trouve dans le fichier [strings.xml] [4] :
 
CacherSélectionnez
  • ligne 17 : le style de l'interface visuelle. Elle est définie dans le fichier [styles.xml] [4] :
 
CacherSélectionnez
  • ligne 18 : une balise d'activité. Une application Android peut avoir plusieurs activités ;
  • ligne 19 : le nom complet de la classe de l'activité ;
  • ligne 20 : son libellé ;
  • ligne 21 : une ligne qui cache le clavier logiciel. A l'affichage de la première vue, le curseur se positionne sur le premier champ de saisie. Le clavier logiciel est alors affiché et cache une partie de la vue. C'est disgracieux. Cette ligne élimine cet affichage ;
  • ligne 23 : l'activité est désignée comme étant l'activité principale ;
  • ligne 25 : et elle doit apparaître dans la liste des applications qu'il est possible de lancer sur l'appareil Android.

XI-E. Le patron des vues

A lire :

  • exemple 6 de [ref2] ;
Image non disponible

On lira complètement l'exemple 6 de [ref2] et on l'exécutera. Le patron [main.xml] des vues Android sera le suivant :

 
CacherSélectionnez
  • ligne 1 : un unique conteneur de composants de type [FrameLayout] identifié par [container] (ligne 3). Le conteneur ne contient aucun composant ;

XI-F. L'activité principale

Image non disponible

L'activité a pour rôle principal de gérer cinq onglets. Lorsque l'un d'eux est cliqué, la vue correspondante doit être affichée. Il y en a cinq. Elles ont été présentées au paragraphe , page .

L'activité Android [MainActivity] est la suivante :

 
CacherSélectionnez
  • ligne 5 : la classe [MainActivity] étend la classe [FragmentActivity]. Ceci est imposé par le modèle AVAT ;
  • ligne 5 : la classe [MainActivity] implémente l'interface [TabListener] car elle gère des onglets. Les méthodes de cette interface sont les méthodes des lignes 27, 32 et 37 ;
  • ligne 12 : l'activité gère cinq vues qui sont mémorisées dans un tableau. Les éléments de celui-ci sont de type [TabVue] :
 
CacherSélectionnez
  • le type [TabVue] associe à un onglet [8] la vue que celui-ci affiche [10] ;

Retour au code de l'activité :

 
CacherSélectionnez
  • ligne 3 : la méthode exécutée par toute activité lorsqu'elle est créée ;
  • ligne 5 : appel de la méthode parent (obligatoire) ;
  • ligne 7 : affiche une image animée en haut et à droite de la vue montrant qu'une opération longue est en cours ;
  • ligne 8 : pour l'instant cette image n'est pas affichée ;
  • ligne 10 : le modèle des vues [main.xml] devient la vue courante ;
  • ligne 12 : la fabrique des objets AVAT est instanciée. On lui passe une classe de configuration sur laquelle on reviendra ;
  • ligne 24 : on demande à la fabrique une référence sur la session AVAT. On s'en servira pour passer des informations d'une vue à l'autre ;
  • ligne 16 : on met dans la session, une URL par défaut pour le service REST. Elle est prise dans le fichier [strings.xml] :
Image non disponible
 
CacherSélectionnez

La ligne 16 de l'activité utilise le message de la ligne 4 de [strings.xml].

Retour au code de l'activité :

 
CacherSélectionnez
  • ligne 9 : on récupère la barre d'action de l'activités. C'est elle qui va contenir les onglets ;
  • ligne 10 : le mode de navigation est celui d'onglets qu'on clique ;
  • lignes 13-21 : on définit les cinq vues de l'application ;
  • lignes 13-14 : pour définir un élément de type [TabVue], il faut fournir deux éléments : un onglet [Tab] et une vue [Vue]. Lorsqu'on clique sur [Tab] alors la vue [Vue] est affichée. L'onglet [Tab] est construit comme suit :
  • actionBar.newTab() : construit un onglet [Tab] et rend sa référence,
  • [Tab].setText(libellé) : fixe un libellé à l'onglet et rend [Tab]. Celui-ci est défini dans le fichier [strings.xml] :
 
CacherSélectionnez
  • [Tab].setTabListener : fixe la classe qui gère les onglets et qui donc implémente l'interface [TabListener], ici this,
  • ligne 14 : la référence de la vue à associer à l'onglet qui vient d'être construit est demandé à la fabrique :
  • 1er paramètre : le n° de l'objet à construire,
  • 2ème paramètre : un tableau d'arguments à passer à la vue. Ici, il n'y a pas d'arguments à passer ;
  • ligne 28 : le 1er onglet est affiché ;
  • ligne 25 : les différentes vues maintiennent en session la liste des Arduinos connectés sous forme d'un tableau. Au départ de l'activité, celui-ci est vide ;

La méthode [] qui affiche certains onglets est la suivante :

 
CacherSélectionnez
  • ligne 7 : on récupère l'onglet n° i ;
  • ligne 8 : on récupère sa position dans la liste des onglets affichés. Le résultat INVALID_POSITION signifie que l'onglet n'est pas affiché ;
  • ligne 9 : si l'onglet n° i doit être affiché ;
  • ligne 11 : s'il n'est pas déjà affiché, alors on l'affiche (ligne 12) ;
  • ligne 14 : l'onglet ne doit pas être affiché ;
  • ligne 16 : si l'onglet est déjà affiché, alors il faut l'enlever (ligne 17) ;

La gestion des onglets est faite avec les trois méthodes de l'interface [TabListener] :

 
CacherSélectionnez
  • ligne 3 : on ne gère que le clic qui sélectionne un onglet ;
  • tab : l'onglet cliqué,
  • fragmentTransaction : un objet qui permet de changer de fragment (Vue) dans le patron [main.xml] ;
  • lignes 7-10 : l'onglet cliqué est cherché dans le tableau des onglets. L'élément trouvé a la position (i-1) dans le tableau ;
  • ligne 12 ; dans le modèle [main.xml], on vient remplacer l'élément nommé [container] par la vue (Vue) associée à l'onglet cliqué ;

XI-G. La configuration de l'application

Image non disponible

L'application est configurée par la classe [Config] suivante :

 
CacherSélectionnez
  • ligne 8 : le booléen verbose contrôle le mode verbeux ou non du modèle AVAT. Le laisser à vrai le temps du débogage ;
  • ligne 10 : fixe un délai maximal pour la réponse du serveur, ici 1 seconde. Au-delà, la couche [DAO] lance une exception ;

XI-H. La fabrique de l'application

Image non disponible

La fabrique est la classe qui fabrique les objets de l'application. Le modèle AVAT essaie de travailler le plus possible avec des interfaces plutôt qu'avec des objets concrets. Cela facilite l'évolution d'une application et ses tests. Les objets concrets sont délégués à une fabrique ayant pour seule méthode :

 
CacherSélectionnez

La méthode [getObject] reçoit deux paramètres :

  • le n° d'objet num de l'objet à construire ;
  • une liste de paramètres pour initialiser l'objet à construire. Ces paramètres sont non typés parce qu'on ne peut prévoir a priori ce qu'ils seront ;

Le squelette de la fabrique est le suivant :

 
CacherSélectionnez

Nous ne présentons ici que certains éléments de la fabrique :

  • lignes 81-86 : la session - instanciée en un seul exemplaire ;
  • lignes 89-99 : les couches [métier] et [DAO] - instanciées en un seul exemplaire ;
  • lignes 102-126 : la vue CONFIG_VUE qui est la 1ère vue présentée à l'utilisateur - instanciée en un seul exemplaire ;
  • lignes 146-167 : l'action CONFIG_ACTION lancée par la vue CONFIG_VUE - instanciée à chaque demande ;
  • lignes 129-143 : la tâche CONFIG_TASK lancée par l'action CONFIG_ACTION - instanciée à chaque demande ;

XI-I. L'interface de la vue [Config]

Image non disponible

La vue [config.xml] est la suivante :

Image non disponible

Le code XML de cette vue est le suivant :

 
CacherSélectionnez
  • ligne 2 : les composants de la vue sont dans " RelativeLayout ". Dans ce conteneur de composants, ceux-ci sont placés les uns par rapport aux autres : " à droite de ", " à gauche de ", " au-dessous de ", " au-dessus de " ;
  • ligne 5 : le conteneur va occuper tout l'espace horizontal de la tablette ;
  • ligne 6 : idem pour l'espace vertical ;
  • ligne 8 : le texte [1] ;
  • ligne 12 : le texte [2] ;
  • ligne 15 : le champ de saisie [3] ;
  • ligne 21 : le message d'erreur [4] ;
  • ligne 24 : le texte [5] ;
  • ligne 27 : le bouton [6] ;
  • ligne 30 : un bouton caché sous le bouton [6] ;
  • ligne 33 : la liste [7] ;

XI-I-1. Le texte [1]

Image non disponible

Le texte [1] est obtenu par le code XML suivant :

 
CacherSélectionnez
  • ligne 2 : son identifiant [txt_TitreConfig]. Ce qui précède [@+id] est obligatoire ;
  • ligne 3 : sa largeur - aussi large que le nécessite le texte affiché ;
  • ligne 4 : sa hauteur - aussi haut que le nécessite le texte affiché ;
  • ligne 5 : le haut du composant sera aligné sur le haut du conteneur ;
  • ligne 7 : le composant aura une marge haute de 20 pixels. Il sera donc 20 pixels dessous le haut du conteneur ;
  • ligne 6 : le composant sera centré horizontalement dans son conteneur ;
  • ligne 8 : le texte à afficher est dans le fichier [Strings.xml] [2] identifié par [txt_TitreConfig] :
 
CacherSélectionnez
  • ligne 9 : la taille du texte est précisée dans le fichier [dimens.xml] [2] identifié par [titre] :
 
CacherSélectionnez

Ligne 3, la taille [titre] est de 30 pixels.

Toutes ces propriétés sont accessibles depuis l'onglet [Graphical Layout] du fichier [config.xml] :

Image non disponible

Les propriétés du composant [1] s'obtiennent par un clic droit :

Image non disponible

XI-I-2. Les autres composants de la vue

Les autres composants de la vue sont les suivants :

Image non disponible

Id

Type

Rôle

1

txt_TitreConfig

TextView

titre de la vue

2

txt_UrlServiceRest

TextView

libellé

3

edt_UrlServiceRest

EditText

saisie de l'URL du service REST

4

txt_MsgErreurIpPort

TextView

un message d'erreur affiché si l'URL saisie est incorrecte

5

txt_arduinos

TextView

libellé

6

btn_Rafraichir

Button

pour régénérer la liste des Arduinos connectés

6

btn_Annuler

Button

pour annuler la connexion au serveur si celle-ci est trop longue. Il est caché par le bouton [Rafraîchir].

7

ListViewArduinos

ListView

pour afficher la liste des Arduinos connectés

La description XML est la suivante :

 
CacherSélectionnez

XI-J. Le code de la vue [Config]

Image non disponible

Nous décrivons maintenant la vue V du modèle AVAT :

Image non disponible

Dans le modèle AVAT, la vue V saisit des données dans une interface Android. La validité de ces données est vérifiée. Si elles sont valides, la vue V lance une action A en lui passant les données saisies. L'action A a deux possibilités :

  • si l'action A à faire doit exécuter une méthode réseau de la couche [métier], alors elle doit passer par une tâche T ;
  • sinon l'action A fait exécuter une méthode de la couche [métier] ;
  • la tâche asynchrone T exécute une méthode de la couche [métier] dans un thread à part ;
  • la tâche T rend son résultat à l'action A qui le rend à la vue V ;

XI-J-1. Squelette de la classe [ConfigVue]

Le code de la vue [ConfigVue] de configuration de l'application est le suivant :

 
CacherSélectionnez
  • ligne 5 : la classe [ConfigVue] étend la classe [LocalVue] qui étend elle-même la classe [Vue] du modèle AVAT. Nous reviendrons un peu plus loin sur la classe [LocalVue] ;
  • lignes 23-26 : la méthode [onCreateView] définit la vue associée au fragment. C'est la vue XML [config.xml] que nous venons de décrire ;
  • lignes 29-69 : la méthode [onActivityCreated] récupère les références des composants de la vue [config.xml] ;
  • lignes 41, 77 : la méthode [doRafraîchir] traite le clic sur le bouton [Rafraichir] ;

XI-J-2. La méthode [doRafraichir]

Elle traite le clic sur le bouton [Rafraichir]. Son code est le suivant :

 
CacherSélectionnez
  • lignes 4-6 : les données saisies sont vérifiées. Si elle ne sont pas valides, on retourne à l'UI (ligne 5) ;
  • ligne 8 : on mémorise en session l'URL du service REST. La session est un champ de la classe parent [LocalVue] ;
  • ligne 11 : on met un tableau d'Arduinos vide en session ;
  • ligne 13 : la liste vide est affichée avec la méthode [showArduinos] de la classe parent [LocalVue]. Cela permet d'afficher une liste vide, le temps que l'action de remplissage de la liste fasse son effet ;
  • ligne 15 : l'action chargée de demander la liste des Arduinos connectés est instanciée par la fabrique. Les paramètres sont les suivants :
  • n° de l'action à instancier,
  • une référence this sur le boss de l'action (la vue),
  • l'identifiant de l'action ;
  • ligne 17 : on signale à la classe parent [Vue] que l'action est lancée ;
  • ligne 19 : on met en place l'attribut visuel qui signale qu'une opération potentiellement longue est en cours ;
  • ligne 21 : l'action [configAction] est lancée. On lui passe l'URL du service REST ;
  • ligne 23 : on demande à la classe parent de nous avertir de la fin des tâches.

XI-J-3. Gestion des résultats de l'action

L'action [configAction] va rendre la liste des Arduinos connectés ou bien une exception si cette liste n'a pu être obtenue. Les méthodes qui récupèrent ces résultats sont les méthodes [notifyEvent] et [notifyEndOfTasks].

La méthode [notifyEvent] est la suivante :

 
CacherSélectionnez
  • ligne 2 : la méthode [notifyEvent] gère les événements WORK_INFO et WORK_TERMINATED que lui envoie l'action. Elle reçoit trois paramètres :
  • worker : l'action qui envoie la notification,
  • eventType : le type de notification. Il y en a trois WORK_STARTED, WORK_INFO et WORK_TERMINATED,
  • info : une information facultative ;
  • ligne 4 : quelque soit l'événement, celui-ci est passé d'abord à la classe parent. L'événement [WORK_TERMINATED] va être ainsi traité ;
  • ligne 6 : l'événement [WORK_INFO] est traité. Il transporte avec lui une information que la vue va afficher ;
  • ligne 8 : l'information transmise par l'action est mémorisée ;
  • lignes 10-11 : si l'information mémorisée est une exception, alors celle-ci est affichée par une méthode [showException] de la classe parent [LocalVue] ;
  • ligne 12 : si l'information mémorisée est une collection alors il s'agit de la liste des Arduinos ;
  • ligne 15 : la collection est transformée en tableau ;
  • ligne 17 : ce tableau est mis en session. Il sera utilisé par toutes les autres vues ;
  • ligne 19 : la liste des Arduinos est affichée et remplace donc la liste vide qui avait été affichée initialement ;

La méthode [notifyEndOfTasks] est la suivante :

 
CacherSélectionnez
  • ligne 2 : la méthode [notifyEndOfTasks] est appelée par la classe parent [Vue] lorsque toutes les tâches sont terminées. Ici, il s'agit de la fin de l'unique action qui a été lancée ;
  • ligne 4 : on cache les éléments visuels qui indiquaient qu'une opération était en cours ;
  • ligne 6 : si on a eu une exception, alors on n'affiche que l'onglet de configuration (ligne 7), sinon on affiche tous les onglets (ligne 9). En effet, à partir du moment où il existe une liste d'Arduinos, on peut travailler avec. Aussi les quatre onglets qui permettent d'envoyer des commandes aux Arduinos sont-ils affichés. Le champ [mainActivity] est un champ de la classe parent [LocalVue]. la méthode [showTabs] a été présentée au paragraphe , page .

XI-J-4. La méthode [pageValid]

La méthode [pageValid] vérifie la valité des données saisies, ici une URL. Son code est le suivant :

 
CacherSélectionnez
  • ligne 4 : l'URL saisie est récupérée ;
  • ligne 7 : on essaie de créer une URI (Unique Resource Identifier) à partir de cette URL. Si l'URL n'a pas un format correct, une exception sera lancée ;
  • ligne 10 : s'il y a exception, un message d'erreur est affiché ;
  • ligne 20 : la méthode [showErreur] est utilisée pour afficher une erreur. Son premier paramètre est un message d'erreur à afficher et son second une exception à afficher ;
  • ligne 22 : si on a une exception, on utilise la méthode [showException] de la classe parent [LocalVue] pour l'afficher ;
  • ligne 27 : sinon, on affiche le message d'erreur ;
  • lignes 30-31 : en cas d'erreur de saisie de l'URL, une liste d'Arduinos vide est mise en session et affichée ;
  • ligne 15 : s'il n'y a pas d'erreur, on efface un éventuel message d'erreur qui aurait pu être affiché lors d'une saisie précédente.

XI-J-5. Les autres méthodes de la vue

Les autres méthodes de la vue ont peu de logique.

 
CacherSélectionnez

Les méthodes [showHourGlass] de la ligne 4 et [hideHourGlass] de la ligne 13 sont des méthodes de la classe parent [LocalVue].

  • ligne 2 : la méthode [beginWaiting] est utilisée pour afficher une attente ;
  • ligne 4 : on affiche l'image animée qui indique qu'une opération est en cours ;
  • ligne 6 : le bouton [Rafraichir] va être caché ;
  • ligne 7 : le bouton [Annuler] est affiché ;
  • ligne 11 : la méthode [cancelWaiting] est utilisée pour arrêter l'attente ;
  • ligne 13 : on cache l'image animée qui indique qu'une opération est en cours ;
  • ligne 15 : le bouton [Rafraichir] est affiché ;
  • ligne 16 : le bouton [Annuler] est caché ;

XI-J-6. Annulation des tâches

Avec le bouton [Annuler], l'utilisateur peut annuler l'action lancée. La méthode qui traite le clic sur le bouton [Annuler] est la suivante :

 
CacherSélectionnez
  • ligne 5 : la méthode qui traite le clic sur le bouton [Annuler] ;
  • ligne 7 : on demande à la classe parent d'annuler toutes les actions. Ici, il n'y en qu'une ;
  • ligne 9 : on arrête l'attente ;
  • ligne 11 : seul l'onglet [CONFIG] est affiché. Les autres disparaissent.

XI-K. La classe parent [LocalVue]

Image non disponible

La classe [LocalVue] est la classe parent de toutes les vues. Elle factorise les comportements communs aux différentes vues. Son code est le suivant :

 
CacherSélectionnez
  • ligne 6 : la classe [LocalVue] étend la classe [Vue] du modèle AVAT. C'est obligatoire ;
  • ligne 13 : la méthode exécutée lorsque la vue est créée ;
  • ligne 15 : l'événement est passé à la classe parent ;
  • ligne 17 : on demande une référence de la session à la fabrique ;
  • ligne 19 : l'activité [MainActivity] est injectée dans toutes les vues dans un champ activity de type Activity. Afin d'éviter des transtypages dans les différentes vues, cette activité est mémorisée avec le bon type dans le champ mainActivity de la ligne 10 ;
  • les lignes 35 et 40 agissent sur le composant qui a été défini ainsi dans [MainActivity] :
 
CacherSélectionnez

La méthode de la ligne 23 affiche les Arduinos de la façon suivante :

 
CacherSélectionnez
  • ligne 2 : la méthode admet les paramètres suivants :
  • le composant [ListView] chargé d'afficher les Arduinos,
  • un booléen selectable qui indique si l'affichage d'un Arduino dans la liste doit se faire avec une case à cocher ou non. Elle se fera sans case à cocher dans la vue [ConfigVue] avec une case à cocher dans les autres vues,
  • le tableau des Arduinos déjà sélectionnés. Il faut cocher leur case. Ce paramètre n'a pas été utilisé dans l'exemple. Ce travail reste à faire (ligne 9) ;
  • ligne 5 : la liste des Arduinos à afficher est récupérée dans la session ;
  • ligne 6 : cette liste est utilisée pour alimenter le [ListView] (ligne 8) au moyen d'un ArrayAdapter (ligne 6).

XI-L. L'adaptateur [ListArduinosAdapter]

Revenons sur le code précédent :

 
CacherSélectionnez
  • ligne 5 : le [ListView] listArduinos est alimenté par un adaptateur. C'est lui qui fournit au [ListView] les données à afficher ;
  • ligne 3 : la définition de l'adaptateur. Il reçoit quatre paramètres :

L'adaptateur [ListArduinosAdapter] est le suivant :

Image non disponible
  • en [1], la classe de l'adaptateur du [ListView] ;
  • en [2], le fichier [listarduinos_item.xml] est la définition XML des lignes affichées par le [ListView] ;
  • en [3], la forme d'une ligne du[ListView].

Le code du fichier [listarduinos_item.xml] est le suivant :

 
CacherSélectionnez
Image non disponible
  • lignes 9-15 : la case à cocher ;
  • lignes 17-33 : l'identifiant de l'Arduino ;
  • lignes 35-53 : la description de l'Arduino.

La classe [ListArduinosAdapter] exploite cette définition XML :

 
CacherSélectionnez
  • ligne 27 : pour générer les lignes du [ListView], la méthode [getView] est appelée de façon répétée. Elle rend la ligne à afficher. Le 1er paramètre est le n° de la ligne dans le [ListView]. Le second paramètre est la ligne actuellement à cette position. Ce paramètre est null lors de la première génération de la ligne ;
  • ligne 29 : on récupère l' "ancienne " ligne ;
  • ligne 31 : si cette ligne existe déjà (row!=null) elle est renvoyée telle quelle (ligne 44). Si elle n'existe pas (row==null), alors on la crée (lignes 32-41) ;
  • ligne 33 : la ligne est créée à partir de sa définition XML [listarduinos_item.xml] ;
  • lignes 34-35 : on récupère les références des composants TextView qui doivent afficher respectivement, l'identifiant et la description de l'Arduino à afficher ;
  • lignes 37-38 : les textes de ces deux composants sont intialisés ;
  • ligne 40 : on récupère la référence de la case à cocher ;
  • ligne 41 : selon que le constructeur a été appelé avec la propriété selectable à vrai ou faux, on montre ou cache la case à cocher.

XI-M. La méthode [getSelectedArduinos] de la vue [LocalVue]

Dans les vues [PINWRITE], [PINREAD], [BLINK] et [COMMANDS], l'utilisateur sélectionne dans une liste, les Arduinos concernés par la commande qu'il va exécuter. On a donc besoin de savoir quels sont les arduinos qui ont été sélectionnés par l'utilisateur. Cela est obtenu par la méthode [getSelectedArduinos] de la vue [LocalVue] :

Image non disponible
 
CacherSélectionnez
  • ligne 4 : on récupère en session le tableau des Arduinos connectés ;
  • ligne 5 : la liste des Arduinos sélectionnés par l'utilisateur ;
  • ligne 7 : on parcourt les éléments du [ListView] ;
  • ligne 8 : on récupère une référence sur la case à cocher de la ligne n° i ;
  • lignes 9-10 : si la case est cochée, alors on ajoute l'Arduino n° i à la liste des Arduinos sélectionnés ;
  • ligne 14 : on rend un tableau plutôt qu'une liste.

XI-N. L'action [ConfigAction]

Image non disponible

La classe [ConfigAction] est chargée d'obtenir la liste des Arduinos connectés auprès du serveur REST.

Image non disponible

Cette action va déboucher sur l'ouverture d'une connexion réseau vers le serveur REST. Pour cela, on a besoin d'une tâche asynchrone.

L'action [ConfigAction] est la suivante :

 
CacherSélectionnez
  • ligne 5 : la classe [ConfigAction] étend la classe [Action] du modèle AVAT. C'est obligatoire ;
  • ligne 9 : la méthode exécutée par l'action lorsque la vue la lance. Ici, elle reçoit un paramètre : l'URL du service REST ;
  • ligne 12 : on demande à la fabrique la tâche asynchrone de n° [Factory.ConfigTask]. On passe à la fabrique deux paramètres :
  • this : une référence sur le boss de la tâche, l'action elle-même ,
  • configTask : l'identifiant de la tâche créée ;
  • ligne 14 : on lance la tâche avec les paramètres qu'a reçus l'action ;
  • ligne 16 : l'action attend la fin des tâches asynchrones qu'elle a lancées, ici une seule.
  • ligne 26 : en tant que boss, l'action va voir passer dans la méthode [notifyEvent] les notifications des tâches qu'elle a lancées.Cette méthode a trois paramètres :
  • worker : la tâche qui envoie la notification,
  • eventType : le type de notification,
  • info : une éventuelle information ;
  • ligne 28 : la notification est passée à la classe parent pour que celle-ci puisse envoyer à son tour la notification [endOfTasks] ;
  • ligne 30 : si la notification est de type WORK_INFO, la notification est passée au boss de l'action et celle-ci se substitue au worker qui a envoyé cette notification (paramètre this de la ligne 32) ;
  • ligne 20 : la classe parent active cette méthode de la classe fille lorsque toutes les tâches lancées par celle-ci sont terminées ;
  • ligne 22 : l'action envoie alors à son boss (la vue) la notification indiquant qu'elle a terminé son travail.

XI-O. La tâche [ConfigTask]

Image non disponible

La tâche [ConfigTask] est chargée d'obtenir la liste des Arduinos connectés auprès du serveur REST.

Image non disponible

Son code est le suivant :

 
CacherSélectionnez
  • ligne 5 : la classe [ConfigTask] étend la classe [Task] du modèle AVAT. C'est obligatoire ;
  • ligne 8 : l'information produite par la tâche ;
  • ligne 16 : la méthode [onPreExecute] est exécutée avant la méthode asynchrone [doInBackGround]. Elle est exécutée dans le thread de l'interface comme le sont également l'activité, l'action et la vue ;
  • ligne 19 : la tâche envoie à son boss la notification WORK_STARTED pour indiquer qu'elle a démarré ;
  • ligne 24 : la méthode [doInBackGround] est exécutée dans un thread à part de celui de l'UI. Elle reçoit les paramètres que lui a donnés l'action qui l'a lancée ;
  • ligne 27 : on récupère l'unique paramètre qu'a transmis l'action ;
  • ligne 30 : on demande à la fabrique une référence sur la couche [métier] ;
  • ligne 32 : la méthode [getArduinos] de la couche [métier] est exécutée. On mémorise le résultat de cette méthode ;
  • ligne 35 : s'il se produit une exception, elle est mémorisée ;
  • ligne 42 : la méthode [onPostExecute] est exécutée après la méthode asynchrone [doInBackGround]. Elle est exécutée dans le thread de l'interface comme le sont également l'activité, l'action et la vue ;
  • ligne 45 : l'information produite par la méthode [doInBackGround] est transmise au boss (l'action) ;
  • ligne 47 : la tâche signale a son boss (l'action) qu'elle a terminé son travail.

XI-P. La couche []

La couche [métier] est chargée d'obtenir auprès du serveur REST les informations demandées par les vues.

Image non disponible

XI-P-1. Le projet Eclipse

Le projet Eclipse de la couche [métier] est le suivant :

Image non disponible
  • en [1], le projet Eclipse est un projet Maven ;
  • en [2], les dépendances Maven. Il y en a une : celle sur le projet [android-dao] de la couche [DAO] du client Android. Les autres en découlent.

XI-P-2. Les dépendances Maven

Le fichier [pom.xml] du projet est le suivant :

 
CacherSélectionnez
  • lignes 5-7 : l'identité Maven de la couche [métier] ;
  • lignes 19-21 : la couche [métier] a une dépendance sur la couche [DAO] du client Android.

XI-P-3. L'interface de la couche [métier]

L'interface [IMetier] de la couche [métier] est la suivante :

 
CacherSélectionnez

Cette interface est celle de l'interface [IMetier] du serveur décrite au paragraphe , page . Les méthodes correspondent une à une avec une unique différence : l'interface [IMetier] du client Android a un paramètre supplémentaire pour chaque méthode : l'URL du service REST.

XI-P-4. La méthode [getArduinos]

Nous avons vu que la tâche [ConfigTask] a appelé la couche [métier] de la façon suivante :

 
CacherSélectionnez

La méthode [getArduinos] est la suivante :

 
CacherSélectionnez
  • la méthode [getArduinos] du client doit appeler la méthode [getArduinos] du serveur REST. L'URL de cette méthode a été définie de la façon suivante (cf paragraphe , page ) :
 
CacherSélectionnez

On a donc une URL sans paramètres.

  • l'URL complète de la méthode est construite ;
  • ligne 5 : on demande à la couche [DAO] de se connecter à cette URL et d'en récupérer la réponse JSON. Les paramètres sont les suivants :
  • " get " : la méthode HTTP à utiliser pour se connecter à l'URL,
  • urlService : l'URL à laquelle se connecter ;
  • null : un dictionnaire pour les paramètres d'une commande HTTP POST. Ici, il s'agit d'un GET. Donc on passe un pointeur null,
  • ligne 5 : la méthode [dao.executeRestService] va rendre une collection d'Arduinos sous la forme d'une chaîne JSON ou bien va lancer une exception de type [DomotiqueException]. Cette dernière n'est pas gérée. Elle va remonter jusqu'à la vue où elle sera affichée ;
  • ligne 9 : la chaîne JSON récupérée est transformée en type Collection<Arduino> et rendue à la tâche [ConfigTask] ;
  • ligne 12 : cas où la chaîne JSON récupérée est invalide.

XI-Q. La couche []

La couche [DAO] exécute les demandes de la couche [métier]. C'est elle qui véritablement se connecte au serveur REST :

Image non disponible

XI-Q-1. Le projet Eclipse

Le projet Eclipse de la couche [DAO] est le suivant :

Image non disponible
  • en [1], le projet Eclipse est un projet Maven ;
  • en [2], les dépendances Maven. Il y en a deux :
  • celle sur le projet [domotique-entities] déjà utilisé pour le serveur. Ce projet rassemble les objets que s'échangent le client Android et le serveur REST ,
  • celle sur la bibliothèque [spring-android-rest-template] qui est un client REST fourni par le framework Spring ;

XI-Q-2. Les dépendances Maven

Le fichier [pom.xml] est le suivant :

 
CacherSélectionnez
  • lignes 4-6 : l'identité Maven de la couche [DAO] du client Android ;
  • lignes 22-26 : la dépendance sur la bibliothèque [spring-android-rest-template] ;
  • lignes 27-31 : la dépendance sur le projet [domotique-entities] ;
  • lignes 14-18 : le site où trouver la dépendance [spring-android-rest-template].

XI-Q-3. Le code de la couche [DAO]

Le code de la couche [DAO] a été décrit dans [ref2] au paragraphe 4.4.2, page 69. Vous êtes invités à lire ce paragraphe. La couche [DAO] est à utiliser telle quelle. Elle vous sera donnée.

XI-R. Les tests

Testez la vue [ConfigVue] :

Image non disponible

Pour les tests :

  • vous devez configurer le réseau du PC et des Arduinos :Image non disponible
  • lancez votre serveur REST. Vérifiez-le ;
  • testez votre client Android.

XI-S. Travail à faire

Nous venons d'expliquer toute la chaîne d'exécution pour la vue [ConfigVue] :

Image non disponible

 : En suivant cet exemple, réalisez successivement les différents onglets de l'application présentés au paragraphe , page .


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Serge Tahé. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.