Développer pour Androïd

P1030317.JPG

 

 

Octobre 2013

 

Philippe Garraud, formateur indépendant

 


 

Sommaire

1.      Outils de développement 4

1.1.     Bundle complet 4

1.2.     Compléter Eclipse. 4

2.      La cible. 4

3.      Créer un projet android. 6

4.      Déployer sur la cible. 6

5.      Progresser. 7

6.      HelloWorld. 7

6.1.     Définir le visuel 9

6.2.     Coder les traitements. 9

7.      Un bouton de commande. 10

7.1.     Modifier le layout 10

7.2.     Déploiement et tests. 11

8.      Adapter le lay out 12

9.      Les activités. 12

9.1.     Un peu de théorie. 12

9.2.     Intent 12

9.3.     Lancer une activité. 13

9.4.     Créer l’activité : 13

9.5.     Récupérer le résultat d’une activité. 14

9.5.1.     Coder dans l’activité principale. 14

9.5.2.     Coder dans l’activité appelée. 15

10.       Les fragments. 16

10.1.       Introduction. 16

10.2.       Fragment statique. 16

10.3.       Fragment dynamique. 17

11.       Les listes. 20

11.1.       ListView avec liste en dur. 20

11.2.       ListView avec liste calculée. 21

11.3.       Répondre à un choix sur la ListView. 22

12.       Navigation. 22

12.1.       Navigation par menu. 22

12.2.       Navigation par tab. 23

12.3.       Navigation swipe. 24

12.4.       Navigation Liste Détail 26

12.4.1.       Création de la liste. 27

12.4.2.       Création de la zone de détails. 28

12.5.       Adapter l’interface à l’écran. 29

12.5.1.       Faible largeur ou portrait 29

12.5.2.       Grande largeur ou paysage. 30

13.       Utiliser des images. 31

13.1.       Images statiques. 31

13.2.       Images téléchargées. 31

13.3.       Charger une image en mode asynchrone. 32

13.4.       La classe AsyncTask. 32

13.4.1.       Coder la classe. 32

13.4.2.       Utiliser la classe. 33

13.5.       Utiliser Async Task pour récupérer l’image. 34

14.       Les services Web. 37

15.       Service web rest 37

15.1.       Envoyer une requête Rest 38

15.2.       Décoder une réponse Rest, JSON. 39

16.       Service web soap. 40

16.1.       Appeler un service SOAP. 42

16.2.       Analyser une réponse Soap. 43

 

 

 


 

 

1.   Outils de développement

 

1.1.                  Bundle complet

 

Le plus simple est de télécharger le  bundle complet

 

http://developer.android.com/sdk/index.html

 

Celui-ci contient

 

·       Eclipse JUNO et les plugins pour créer des projets Androïd.
le SDK pour la version 4.3 d’Androïd

·       Un gestionnaire de SDK SDK manager

·       Un simulateur et son outil de configuration AVD manager.

·       Un lien vers le tutoriel

 

1.     Télécharger puis décompresser, il n’y a pas d’installation.

 

2.     Compléter le SDK : Lancer le SDK manager et ajouter le SDK qui correspond à votre cible

 

3.     Paramétrer l’émulateur : Lancer AVD manager et définissez une ou plusieurs cible

 

 

1.2.                  Compléter Eclipse

 

Si vous avez déjà installé Eclipse vous pouvez le compléter par la procédure ci après. Ignorer  ce chapitre si vous avez installé le bundle complet.

 

http://developer.android.com/tools/sdk/eclipse-adt.html

 

 

 

 

2.   La cible

 

Le plus motivant sera d’installer et de tester vos applications sur votre téléphone ou votre tablette.

 

Un débug sur cible est possible si vous avez le pilote adéquate.

Google fournit quelques pilotes  ici : http://developer.android.com/sdk/win-usb.html

 

Vous pouvez également tenir les pilotes à jour avec le SDK manager.
Si Google ne vous fourni pas de pilote, rechercher sur le site de votre fournisseur.

 

 

 

 

Sinon vous pouvez utiliser un émulateur. Celui inclus avec le bundle convient, mais il très lent. Voici quelques alternatives :

 

http://www.softonic.fr/s/emulateur-android-pc

 

 

Windroy : Emule bien Androïd. Pour déployer vos applications, il faut recopier le .apk dans le répertoire Windroy\data\app cela provoque l’installation. De fait cela fonctionne mal, il faut souvent redémarrer Windroy

 

YouWave  http://youwave.com/download.html est disponible en shareware 20 $, période d’évaluation 10 jours

 

GenyMotion  http://genymotion.softonic.fr/  est bien coté. Son installation nécessite une machine virtuelle (fournie)

 

 


 

 

3.   Créer un projet android

 

Voici quelques liens où trouver de la documentation :

 

http://developer.android.com/sdk/index.html

 

http://developer.android.com/guide/faq/commontasks.html

 

http://android.developpez.com/cours/

 

 

Voir aussi et surtout dans votre répertoire d’installation du SDK  /docs

 

 

4.   Déployer sur la cible.

 

J’ai acheté une tablette Archos 97 carbon sous android 4.

Le transfert de fichier depuis l’ordinateur fonctionne parfois mal mais ici c’est suffisant. Par contre pour déboguer directement depuis éclipse, il faut un pilote windows adapté à la tablette, il ne semble pas encore disponible.

 

Pour le moment :

Tester et bien mettre au point sur PC avec l’émulateur.

Quand c’est ok demandé à Eclipse de générer une application signée.

 

http://mathias-seguy.developpez.com/cours/android/retrouver-clef-mapview/

 

Ensuite

·       Recopier le fichier apk sur la tablette

·       Cliquer sur le fichier apk è la tablette propose d’installer.

 

 


 

5.   Progresser.

 

Nous allons exécuter une série d’exercices pour découvrir et comprendre la programmation sous android. Le présent document s’inspire du tutoriel de Google, qui est très bien fait.

6.   HelloWorld

 

Explorons les bases du développement Android à partir d’un exemple simple :

 

Sous Eclipse créer un projet Android :

 

 

 

Continuer avec les options par défaut. Dans le dernier écran, vous pouvez choisir ceci :

 

 

 

 

Le grand principe de la programmation Android est de séparer la définition de la vue et le code java:


 

 

 

6.1.                  Définir le visuel

 

La vue est définie dans un fichier xml que vous trouverez en

 

res\layout\activity_main.xml   (le chemin est imposé mais le nom est libre)

 

Voici sa copie :

 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context=".MainActivity" >

 

    <TextView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/hello_world" />

 

</RelativeLayout>

 

Remarquer l’essentiel de la syntaxe

·       Une balise layout

·       Un ou plusieurs éléments, ici une zone de texte

 

6.2.                  Coder les traitements

 

Il est dans src\eu.garraud.hello1\MainActivity.java

 

package eu.garraud.hello1;

 

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

 

public class MainActivity extends Activity {

 

    @Override

    protected void onCreate(Bundle savedInstanceState)

{

        super.onCreate(savedInstanceState);

 

        setContentView(R.layout.activity_main);

 

       }//fin onCreate

}//fin classe

 

Le point important pour le moment, c’est la méthode onCreate qui comme son nom l’indique est lancée au chargement de la vue. L’instruction setContentView permet de lier la classe et le fichier layout.

 

7.   Un bouton de commande.

 

Dans cet exercice nous allons :

 

Modifier le layout

Ajouter un bouton de commande

Ajouter une fonction événementielle, pour sur un clic modifier la zone de texte.

 

7.1.                  Modifier le layout

 

Effacer complètement le fichier activity_main.xml.

 

En mode graphique :

·       Depuis la palette ajouter un linear layout, observer la fenêtre outline, regarder les outils pour modifier les propriétés.

·       Dans ce layOut, ajouter un bouton, renommer le btnHello.

·       Ajouter de même une zone de texte txtHello.

·       Regarder le xml obtenu.

·       Dans la définition du bouton ajouter

·       android:onClick="clickHello"

·       Coder la fonction événementielle :

 

public void clickHello(View objetClic)

    {

       txtHello.setText("nous sommes tous la");

    }//fin onClick

 

Pour que txtHello soit connu dans votre code vous devez faire deux choses

 

Le déclarer en donnée membre

 

       private TextView txtHello ;

 

Le lier au layout (à coder dans onCreate)

 

        txtHello = (TextView) findViewById(R.id.txtHello);

Pour bien comprendre, regarder le fichier généré :

 

src\gen\eu.garraud\R .java

 

Noter également que la présence de texte en dur dans le fichier layOut est déconseillée. D’où la présence des fichiers res\values.

 

7.2.                  Déploiement et tests

 

·       Générer un .apk à l’aide de l’outil AndroidToolsàExport Signed Applications Package.

·       Recopier vers votre matériel

·       Installer

·       Lancer

 

 

Exercice Android001

Coder ceci et tester le.

 

Exercice Android002

Coder de même une calculette. Deux champs de saisie pour les opérateurs, quatre boutons pour les calculs, un champ de résultat.

 

Alternative :

 

Déclarer les fonctions événementielles dans le layout est le plus simple. Parfois cependant vous devrez le faire à la mode Swing, c’est possible. C’est parfois nécessaire.

 

Exercice Android003

Refaire l’exercice 001 avec une classe écouteur.

 

 

 

8.   Adapter le lay out

 

Une application androïd doit pouvoir fonctionner sur plusieurs tailles d’écrans et en mode paysage comme en mode portrait. Vous avez, à cet effet la possibilité de définir plusieurs layout dans le répertoire res . Par exemple, pour un affichage en mode paysage,  il faut créer un sous répertoire layout-land et y inclure le fichier xml adapté. Bien entendu le sous répertoire layout est utilisé par défaut.

 

Exercice Androïd004

Fournir à votre application calculette un layout différent en paysage et en portrait.

 

9.   Les activités.

 

9.1.                  Un peu de théorie

 

Androïd implémente quatre types de composants :

·       Les activités

·       Les services

·       Les BroadcastReceiver

·       Les contentProvider.

 

Pour le moment nous nous intéressons aux activités.

 

Une activité est une classe java qui étend Activity.

A chaque activité est associé un visuel (un écran) définit dans un fichier xml de layout. Nous avons donc déjà créé une activité.

 

Pour chaque écran, nous devons créer une activité. Changer d’écran est donc changer d’activité. Lorsque l’opérateur change d’écran les activités s’empilent, mais elles ne s’arrêtent pas vraiment.

 

Cet aspect est complexe, mais il n’est pas nécessaire de tout comprendre pour l’instant. Voir : http://developer.android.com/training/basics/activity-lifecycle/index.html pour plur de détails.

 

9.2.                  Intent

 

Une activité a une mission à remplir, c’est l’intent. L’intent défini ce que l’on attend de l’activity. Plusieurs activities  peuvent être candidates à remplir un intent, en ce cas le système demandera à l’opérateur de choisir. Vous rencontrez ceci par exemple si vous avez plusieurs applications pour visualiser des photos.

Pour le moment, contrairement à ce qui est indiqué plus haut, nous créerons un item spécifique pour chacune de nos activités, (donc pour chaque écran).

9.3.                  Lancer une activité

 

Il faut tout d’abord créer un intent :

 

             Intent intent = new Intent(this, DisplayMessageActivity.class);

 

Dans ce constructeur :

·       this est le context appelant, ici nous même

·       DisplayMessageActivity.class  est l’activité à lancer

 

Si nous souhaitons passer des informations à l’activité, il faut ajouter :

 

             String message = “bonjour”;

             intent.putExtra(EXTRA_MESSAGE, message);

      

 

Extra_Message est le nom du paramètre, on le définit sous la forme d’une constante de classe,  afin de la retrouver facilement. Il est galant d’indiquer son nom de domaine

 

 

public final static String EXTRA_MESSAGE ="garraud.example.twoactivities.MESSAGE";

 

Ensuite, il ne reste plus qu’à lancer l’activité.

 

             startActivity(intent);

 

Dans l’hypothèse, où cette activité serait lancée comme suite à un clic, et où le message serait saisi dans une zone de texte, nous aurions ceci :

 

/** Called when the user clicks the Send button */

       public void sendMessage(View view)

       {

           // Do something in response to button

             Intent intent = new Intent(this, DisplayMessageActivity.class);

             EditText editText = (EditText) findViewById(R.id.edit_message);

             String message = editText.getText().toString();

             intent.putExtra(EXTRA_MESSAGE, message);

             startActivity(intent);

       }//fin sendMessage

 

 

9.4.                  Créer l’activité :

 

Notre nouvelle activité sera une classe, nous pouvons récupérer le paramètre de la manière suivante :

 

@Override

       protected void onCreate(Bundle savedInstanceState)

{

             super.onCreate(savedInstanceState);

             setContentView(R.layout.activity_display_message);

            

             //get the message

             Intent intent = getIntent();

             String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);

             //display

             TextView textView = (TextView) findViewById(R.id.txtMessage);

             textView.setText(message);

       }//fin onCreate

 

 

Permettre la navigation

 

Pour permettre à l’opérateur de revenir à l’activité principale, ajouter dans le onCreate :

 

// Show the Up button in the action bar.

             getActionBar().setDisplayHomeAsUpEnabled(true);

 

Une petite flèche apparait alors dans l’action bar à gauche du titre de l’application.

9.5.                  Récupérer le résultat d’une activité

 

De même qu’une activité peut exploiter une entrée, elle peut fournir une sortie.

 

9.5.1.                       Coder dans l’activité principale

 

Prévoir tout d’abord ces constantes :

 

/      /définir un message pour le paramètre fourni

       public final static String REQUEST_MESSAGE = "eu.garraud.question";

       //définir un message pour le retour

       public final static String ANSWER_MESSAGE = "eu.garraud.reponse";

       //définir un identifiant de l'activité appelante

       public final static int SUB1=1;

 

Il faut ensuite modifier l’appel, comme ceci:

 

startActivityForResult(intent,SUB1);

 

Prévoir une callback pour traiter le retour :

 

@Override

       protected void onActivityResult(int requestCode,

int resultCode, Intent data)

       {   

             if (requestCode==SUB1)

             {

                    String reponse=data.getStringExtra(ANSWER_MESSAGE);

                    this.editText.setText(reponse);

             }

             else

             {

                    this.editText.setText("erreur code request") ;

             }

       }//fin retour Activité

 

Noter que cette callback vaut pour tous les retours, d’où la nécessité d’un identifiant SUB1.

9.5.2.                       Coder dans l’activité appelée.

 

On rappelle l’activité principale, en lui passant le paramètre de retour.

 

       /** Called when the user clicks the Send back button */

       public void sendBackMessage(View view)

       {

           // Do something in response to button

             Intent intent = new Intent();

             String message = this.textReponse.getText().toString();

             intent.putExtra(MainActivity.ANSWER_MESSAGE, message);

             setResult(Activity.RESULT_OK,intent);

             finish();

       }//fin sendMessage

 

 

Exercice Androïd005

Prévoir une activité principale contenant :

·       Une zone de saisie pour la question

·       Un bouton pour ouvrir l’activité appelée

·       Une zone pour afficher la réponse

Prévoir une activité appelée contenant :

·       Une zone pour afficher la question

·       Une zone pour saisir la réponse

·       Un bouton pour envoyer le réponse et retourner à l’activité principale.


 

 

 

10.        Les fragments

10.1.             Introduction

 

La navigation sous Android s’obtient :

 

  1. Par changement complet d’écran, ce qui peut s’obtenir par un changement d’activité.
  2. Par changement d’une partie de l’écran.
  3. A l’aide de Dialog box.

 

La technique 3 est réservée à des questions simples posées à l’utilisateur par l’application. Elle sera étudiée dans un autre chapitre.

 

La technique 1 est utilisée pour les écrans de petites tailles et en orientation portrait.  Elle domine pour les Smartphones. La technique 2 est intéressante pour des écrans plus grands, ou en orientation horizontale. Elle est très utilisée avec les tablettes.

 

Un fragment permet de définir une portion d’écran. Un fragment doit toujours être intégré dans une activité, même si il est unique. A cette réserve près, il y a beaucoup de similitudes entre fragments et activités.  Le visuel  d’un fragment est défini dans un layout xml et son comportement dans une classe java.

 

Selon la taille de l’écran les fragments pourront être disposés de manières différentes par l’activité.

 

Par ailleurs, avec un peu de chance, un même fragment peut être utilisé dans plusieurs applications.

 

10.2.             Fragment statique

 

Commençons par un cas simple. Le fragment statique est chargé au démarrage de l’activité et demeure durant toute l’exécution.

 

Ne pas oublier qu’il faut d’abord créer une activité principale pour lancer l’ensemble.

Prévoir, dans le layout d’ensemble, un emplacement pour le fragment.

Pour ce faire, il faut utiliser la balise fragment.

 

  <!--place holder for a static fragment-->

      

   <fragment android:name="garraud.example.fragmentstatic.HeadLinesFragment"

              android:id="@+id/headline_fragment"

              android:layout_weight="2"

              android:layout_width="0dp"

              android:layout_height="match_parent"

              />

 

La propriété name indique le nom complet de la classe qui implémente le fragment (une erreur à ce niveau serait catastrophique).  Voici un exemple de classe fragment.

 

package garraud.example.fragmentstatic;

 

import android.app.Fragment;

import android.os.Bundle;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

 

public class HeadLinesFragment extends Fragment

{

       @Override

       public View onCreateView(LayoutInflater inflater, ViewGroup container,

                    Bundle savedInstanceState)

       {

             View rootView = inflater.inflate(R.layout.head_lines_fragment,

                          container,false);

             return rootView;   

       }//fin on Create         

}//fin fragment

 

La méthode onCreateView est appelée dès le chargement du layout d’ensemble.

 

  1. inflater est un objet qui va nous permettre de créer le visuel du fragment.
  2. container est l’endroit dans le layout principal où le fragment doit être introduit.
  3. savedInstanceState est utile si le segment est recréé.

 

R.layout.head_lines_fragment est le fichier xml qui définit le visuel.

 

Exercice Androïd006

Afficher un écran contenant un segment statique.

 

10.3.             Fragment dynamique

 

Si des fragments doivent être chargées de manière dynamique durant l’exécution ce sera un peu plus compliqué. Dans le xml d’ensemble remplacer la balise fragment par un simple FrameLayout

 

    <!--place holder for a dynamic fragment-->

     <FrameLayout

        android:id="@+id/article_fragment"       

        android:layout_width="0dp"

        android:layout_height="wrap_content"

        android:layout_weight="1"    

        />

Il n’est plus nécessaire d’indiquer la classe java du fragment, d’ailleurs elle ne sera décidée qu’à l’exécution.


 

 

Le code java du fragment est semblable au cas statique.

 

public class ArticleFragment1 extends Fragment

{

       public ArticleFragment1() {}

      

       @Override

       public void onCreate(Bundle savedInstanceState)

       {

             super.onCreate(savedInstanceState);

       }//fin onCreate

 

       @Override

       public View onCreateView(LayoutInflater inflater, ViewGroup container,

                    Bundle savedInstanceState)

       {

             View rootView = inflater.inflate(R.layout.article_fragment1,

                          container, false);

             return rootView;

       }// fin onCreateView

}// fin fragment 1

 

L’instanciation du fragment se fera dans l’activité principale.

 

public void clickArticle1(View v)

       {

             try

             {

             ArticleFragment1 fragment= new ArticleFragment1();

 

             FragmentManager fmg= getFragmentManager();

             FragmentTransaction ft=fmg.beginTransaction();

              ft.replace(R.id.article_fragment, fragment);

 

//faire ceci si vous souhaitez que le bouton back permette de revenir au fragment précédent

             ft.addToBackStack(null);

 

             ft.commit();

             }

 

             catch(Exception ex)

             {

Toast.makeText(this, ex.toString() + "\n" + ex.getMessage(), Toast.LENGTH_LONG).show();

             }

       }//fin clic Article 1

 

  1. Le fragment manager est un objet qui permet de manipuler les fragments.
  2. Le fragment transaction permet d’exécuter une manipulation sur un ou plusieurs fragments. Il propose des méthodes add replace et remove, dont le premier argument indique le container du fragment et le deuxième est le fragment lui-même.

 

Il est prudent d’anticiper des exceptions. Noter l’usage de Toast pour afficher une alerte.

 

Exercice Android007:

Diviser votre écran en deux panneaux. A gauche des boutons de menu. A droite le contenu. Construisez trois segments différents et essayer de les échanger comme suite à des clics sur les boutons.

 

Remarque sur les versions : Les fragments ont été introduits avec les SDK 11. Les exemples ci-dessus correspondent à la version 15. Cependant pour permettre l’usage des fragments sur des versions plus anciennes d’android, Google procure une bibliothèque support.v4.  Le code est alors légèrement différents des exemples ci-dessus. Veillez à utiliser les imports corrects pour éviter toute confusion.

 

SDK11 et plus                  import android.app.*

SDK4   et plus                  import android.support.v4.app.*

 


 

11.        Les listes

 

11.1.             ListView avec liste en dur.

 

C’est un widget classique, vous pouvez l’ajouter avec la boite à outils, ou taper dans le lay out du code semblable à celui-ci :

 

<ListView

        android:id="@+id/lstStagiaire"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_alignLeft="@+id/txtChoix"

        android:layout_below="@+id/txtChoix"

        android:layout_marginTop="88dp"

        android:entries="@array/stagiaires">

    </ListView>

 

 

android:entries="@array/stagiaires"> définit le tableau qui contient les données, celui-ci est dans les ressources : values\string.xml

 

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="app_name">ListeStatique</string>

    <string name="action_settings">Settings</string>

    <string name="hello_world">Hello world!</string>

     <string-array name="stagiaires">

         <item>LECU</item>

         <item>FAYOLLE</item>

          <item>CORRE</item>

          <item>GARRAUD</item>

    </string-array>

</resources>

 

Il n’y a ici aucun code java spécifique.

 

 

Exercice Android008:

Afficher la liste des couleurs de l’arc en ciel.

 


 

 

 

11.2.             ListView avec liste calculée.

 

Le tableau dans les ressources n’est évidemment plus utile, il faut compléter le code java :

 

Construire un tableau de donnée en java, par exemple :

 

private String[] tabStagiaires;

 

       //Construire la liste par code

             this.lstStagiaires = (ListView)this.findViewById(R.id.lstStagiaires);

             this.tabStagiaires= new String[3];

             this.tabStagiaires[0] = "toto";

             this.tabStagiaires[1] = "titi";

             this.tabStagiaires[2] = "tutu";

Il faut maintenant construire un array adapter et l’affecter à la liste

 

 

       private ListView lstStagiaires;

       private ListAdapter  adStagiaires;

 

adStagiaires = new ArrayAdapter<String>

                          (this,

                          android.R.layout.simple_list_item_activated_1,

                          android.R.id.text1,

                          this.tabStagiaires);

this.lstStagiaires.setAdapter(this.adStagiaires);  

 

public ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects)

Added in API level 1

Constructor

Parameters

context

The current context.

resource

The resource ID for a layout file containing a layout to use when instantiating views.

textViewResourceId

The id of the TextView within the layout resource to be populated

objects

The objects to represent in the ListView.

 

 

Exercice Android009:

Afficher la liste des villes du grand Lyon.

 

11.3.             Répondre à un choix sur la ListView

 

Il faut ajouter un Listener à la liste. Ici, nous utilisons une classe interne

 

 

      

private OnItemClickListener listenList;

      

//classe interne

listenList= new OnItemClickListener()

{

@Override

  public void onItemClick(AdapterView<?> parent, View laVue, int position,long id)

       {           

       txtSelect.setText(((TextView)laVue).getText().toString());

       }

                   

};

this.lstStagiaires.setOnItemClickListener(listenList);

 

 

Exercice Android010:

Compléter en notant la ville sélectionnée.

 

12.        Navigation

 

12.1.             Navigation par menu

 

Le menu est défini dans le fichier xml :

 

res\menu\main.xml

 

Voici un exemple

 

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item

        android:id="@+id/action_settings"

        android:orderInCategory="100"

        android:showAsAction="never"

        android:title="@string/action_settings"/>

   

    <group android:id="@+id/group1"

        android:menuCategory="container"

        android:enabled="true" android:visible="true">

        <item android:id="@+id/item1" android:titleCondensed="A1"

            android:title="Action 1"></item>

        <item android:id="@+id/item2" android:titleCondensed="A2"

            android:title="Action 2"></item>

    </group>

</menu>

 

Vous pouvez vous aider de l’assistant pour le créer.

 

Le menu est affiché à l’ouverture de l’activité par :

 

@Override

    public boolean onCreateOptionsMenu(Menu menu)

    {

        // Inflate the menu; this adds items to the action bar

       // if it is present.

        getMenuInflater().inflate(R.menu.main, menu);

        return true;

    }//fin onCreate

 

Le menu apparait à droite de l’action bar.

Pour réagir au clic vous devez implémenter onOptionItemSelected()

 

@Override

    public boolean onOptionsItemSelected(MenuItem item)

    {   

       // Handle presses on the action bar items   

       switch (item.getItemId())

       {       

       case R.id.item1:           

             this.txtAction.setText("Action 1")  ;   

             return true;       

       case R.id.item2:           

             this.txtAction.setText("Action 2")  ;         

             return true;       

       default:

             this.txtAction.setText("menu inconnu: " + item.getItemId());

             return super.onOptionsItemSelected(item);                 

       }//fin switch

    }//fin on option Menu Selected

 

Ici, nous nous contentons d’afficher un message, mais en général l’action consiste à lancer une nouvelle activité, ou pour le moins afficher un fragment.

 

 

Exercice Android011:

Essayer l’exemple ci-dessus.

 

 

12.2.             Navigation par tab

Le framework android permet de mettre des onglets de navigation dans la barre d’actions. Il suffit de les construire au lancement de l’activité :

 

       @Override

       protected void onCreate(Bundle savedInstanceState)

       {

             super.onCreate(savedInstanceState);

             setContentView(R.layout.activity_main);

 

             // Set up the action bar to show tabs.

             final ActionBar actionBar = getActionBar();

             actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

 

             // For each of the sections in the app, add a tab to the action bar.

             actionBar.addTab(actionBar.newTab().setText(R.string.title_section1)

                          .setTabListener(this));

             actionBar.addTab(actionBar.newTab().setText(R.string.title_section2)

                          .setTabListener(this));

             actionBar.addTab(actionBar.newTab().setText(R.string.title_section3)

                          .setTabListener(this));

       }//fin onCreate

 

Ensuite gérer l’évènement tab, noter qu’ici l’activité est son propre écouteur ; cette approche est généralement déconseillée, mais elle est tolérée ici car il ne peut y avoir qu’un seul tabListener dans une activité.

 

       public void onTabSelected(ActionBar.Tab tab,

                    FragmentTransaction fragmentTransaction)

       {

             // Etrange le paramètre fragmentTransaction n'est pas utilisé.

             // When the given tab is selected, show the tab contents in the

             // container view.

             int tabSelected;

             tabSelected=tab.getPosition()+1;

            

             if (tabSelected==1)

             {

             //do something as load a segment or fire an activity

}// end tab 1

 

Le main layout contient un FrameLayout pour héberger le segment choisi.

 

Eclipse propose de construire un canevas pour cette navigation, il est complexe et risque de brouiller la compréhension. (Attention l’assistant utilise la bibliothèque support V4)

 

 

 

Exercice Android012:

Ajouter des tab dans la barre d’action.

Lancer un traitement différent pour chacune d’elles

 

Les exercices suivant sont complexes ; les stagiaires en retard peuvent sauter directement au chapitre 12 suivant.

 

12.3.             Navigation swipe

 

Une alternative à la navigation par onglet est la navigation par défilement horizontale.

Eclipse propose de construire un canevas pour cette navigation, il est complexe et risque de brouiller la compréhension.

(Attention l’assistant utilise la bibliothèque support V4)

 

Ici le layout principal contient des balises spécifiques

 

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/pager"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".MainActivity" >

 

    <!--

    This title strip will display the currently visible page title, as well as the page titles for adjacent pages.

    -->

 

    <android.support.v4.view.PagerTitleStrip

        android:id="@+id/pager_title_strip"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_gravity="top"

        android:background="#33b5e5"

        android:paddingBottom="4dp"

        android:paddingTop="4dp"

        android:textColor="#fff" />

 

</android.support.v4.view.ViewPager>

 

Il faut programmer un adapter spécifique. Rappelons qu’un adapter a pour mission de fournir chaque élément d’une liste de widgets. Voici le code proposé par l’assistant d’Eclipse, et qu’il faudra adapter :

 

public class SectionsPagerAdapter extends FragmentPagerAdapter

       {

             public SectionsPagerAdapter(FragmentManager fm)

             {

                    super(fm);

             }

             @Override

             public Fragment getItem(int position)

             {

             // TODO modifier ce code pour instancier vos segments

              // getItem is called to instantiate the fragment for the given page.

            

             Fragment fragment = new DummySectionFragment();

             Bundle args = new Bundle();

             args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);

             fragment.setArguments(args);

             return fragment;

             }

 

             @Override

             public int getCount() {

                    // Show 3 total pages.

                    return 3;

             }

 

             @Override

             public CharSequence getPageTitle(int position) {

                    switch (position) {

                    case 0:

                          return getString(R.string.title_section1).toUpperCase();

                    case 1:

                          return getString(R.string.title_section2).toUpperCase();

                    case 2:

                          return getString(R.string.title_section3).toUpperCase();

                    }

                    return null;

             }

       }// fin adapter

 

Pour l’assistant DummySectionFragment est un segment générique. Vous le remplacerez par vos propres segments.

 

Exercice :Androïd013

 Modifier le modèle ci-dessus pour afficher vos segments. Tester et remarquer l’illusion de naviguer sur un ruban

 

 

12.4.             Navigation Liste Détail

 

Notre objectif est de partager notre écran en deux parties :

A gauche une liste, à droite un contenu synchronisé avec le choix dans la liste.

 

Vous pouvez vous inspirez du canevas proposé par Eclipse ; mais celui-ci est plus complexe que nécessaire pour le moment. Nous considérons ici uniquement le cas écran large two panel. Noter également qu’à ce stade de l’exercice l’usage de segments n’est pas impératif. Un écran unique conviendrait.

 

La liste de gauche sera un segment statique, donc chargé au lancement. Le détail de droite sera un segment dynamique qui sera donc rechargé en réponse aux sélections dans la liste.

 

<fragment

        android:id="@+id/livre_list"

        android:name="garraud.example.masterdetail.LivreListFragment"

        android:layout_width="0dp"

        android:layout_height="match_parent"

        android:layout_weight="1"

        tools:layout="@android:layout/list_content" />

 

<FrameLayout

        android:id="@+id/livre_detail_container"

        android:layout_width="0dp"

        android:layout_height="match_parent"

        android:layout_weight="3" />

 

12.4.1.                    Création de la liste

 

Examinons d’abord la mise en place de la liste de gauche. Attention, ici il ne s’agira pas d’une spinner, mais d’un Layout ListView. Dans notre exemple c’est la classe LivreListFragment qui génère la liste. Nous pourrions construire ce segment par nous-même, mais nous allons ici suivre la proposition d’Eclipse. Nous commentons ci-dessous les points essentiels:

 

 

notre segment dérive d’une classe spéciale

public class LivreListFragment extends ListFragment

{     

       private LivreListActivity mCallbacks;

 

       public LivreListFragment() {}

 

       @Override

       public void onCreate(Bundle savedInstanceState)

{

             super.onCreate(savedInstanceState);

 

        

// TODO: replace with a real list adapter and data.

       setListAdapter(new ArrayAdapter<DummyContent.DummyItem>(getActivity(),

                          android.R.layout.simple_list_item_activated_1,

                          android.R.id.text1, DummyContent.ITEMS));

       }//fin onCreate

 

       @Override

       public void onViewCreated(View view, Bundle savedInstanceState) {

             super.onViewCreated(view, savedInstanceState);     

       }//fin onViewCreated

 

       @Override

       public void onAttach(Activity activity) {

             super.onAttach(activity);

 

             //récupérer l'activity appelante.

             mCallbacks = (LivreListActivity)activity;

       }//fin onAttach

 

       @Override

       public void onListItemClick(ListView listView, View view, int position,

                    long id) {

             super.onListItemClick(listView, view, position, id);

 

             //remonter l'évenement vers l'actvité appelante

             mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);

       }//fin onListItem

}//fin classe

 

L’adapter est ici le point central, il référence un layout prédéfini dans le sdk, il est possible de le trouver dans C:….\ androidSqk\platforms\android-15\data\res\layout

Il définit le visuel d’un item, en voici l’essentiel :

 

<TextView android:id="@android:id/text1" xmlns:android="http://schemas.android.com/apk/res/android"/>

 

C’est  donc un simple champ texte. Dans ces conditions les objets à afficher ne peuvent être que des strings ou des objets implémentant toString(). Nous verrons ailleurs qu’il est possible de redéfinir tout cela. Nous nous en satisfaisons pour l’instant.

 

Exercice Android014 :

 Etudier le code proposé par Eclipse et justifier l’emploi d’une définition d’interface pour la callback.

 

12.4.2.                    Création de la zone de détails.

 

Le clic sur la liste est remonté dans l’activité principale, où il doit être traité. Le segment est alors crée. Noter l’utilisation d’un bundle pour transmettre des paramètres au segment.

@Override

       public void onItemSelected(String id)

       {     

       //empaqueter les paramètres

       Bundle arguments = new Bundle();

       arguments.putString(LivreDetailFragment.ARG_ITEM_ID, id);

       LivreDetailFragment fragment = new LivreDetailFragment();

       fragment.setArguments(arguments);

 

       //ajouter le fragment à la view en l'incluant dans livre_detail_container

       //TODO: pour plus de clarté, détailler cette instruction en plusieurs lignes

       getSupportFragmentManager().beginTransaction()

                    .replace(R.id.livre_detail_container, fragment).commit();

 

       }

 

 

 

Le segment est  tout à fait classique. Il faut ici prévoir la réception d’un paramètre.

 

public class LivreDetailFragment extends Fragment

{     

       public static final String ARG_ITEM_ID = "item_id";

       private DummyContent.DummyItem mItem;

 

       public LivreDetailFragment() {} //obligatoire

 

       @Override

       public void onCreate(Bundle savedInstanceState)

{

             super.onCreate(savedInstanceState);

 

             //récupérer les paramètres      

             String leParam=this.getArguments().getString(ARG_ITEM_ID); }//fin onCreate

 

       @Override

       public View onCreateView(LayoutInflater inflater, ViewGroup container,

             Bundle savedInstanceState)

{

       //charger le visuel

             View rootView = inflater.inflate(R.layout.fragment_livre_detail,

                          container, false);

 

             return rootView;

       }//fin onCreateView

}//fin segment

 

 

Exercice  Androïd 015

Gérer une liste de stagiaires. La zone de gauche est la liste des noms, la zone de droite le détail de toutes les informations. Conseil : créer une classe Stagiaire

 

 

 

12.5.             Adapter l’interface à l’écran

 

La disposition two panel ne convient que pour des écrans relativement grands ou en mode paysage. Pour des écrans petits type smartphone on préférera une navigation par remplacement complet de l’écran avec retour arrière. Ceci s’implémente avec des activités. Donc par exemple une activité liste et une activité détail.

 

Cependant développer plusieurs versions de l’application pour pouvoir prendre en compte toutes les tailles d’écran serait pénible. La solution proposée est donc :

 

 

Eclipse propose un modèle de projet dans cette philosophie. Etudier le.

 

Ci après, voici un synoptique qui illustre les liens entre les éléments. Les classes sont en rouge, les layouts xml sont en bleu.

 

12.5.1.                    Faible largeur ou portrait

 

La liste est une activité. Le détail une autre activité qui vient se placer, dans la pile et sur l’écran, au dessus de la liste. Le bouton back permet de revenir à la liste. Chaque fois que l’opérateur change sa sélection dans la liste l’activité est recrée.

 

L’activité principale :

LivreListActivity.java

Activity_livre_list.xml  contient un fragment LivreListFragment.java (sans xml)

 

LivreListFragment.java hérite d’un layout standard d’Android ListFragment

 

ListFragment implémente l’essentiel de la gestion de liste, c’est pourquoi il n’est pas utile de définir le layout par un fichier xml. Il faut cependant redéfinir quelques méthodes en particulier le chargement des données qui se fait avec un setListAdapter(). L’événement sélection est renvoyé vers LivreListActivity.java via une définition de callbacks .

 

A chaque changement de sélection une activité est crée:

LivreDetailActivité.java

activite_livre_detail.xml est un simple container identifié @+ id/livre_détail_container

 

L’activité va créer un LivreDetailFragment.java àfragment_livre_detail.xml  qui sera inclus dans le container

12.5.2.                    Grande largeur ou paysage

 

Ici le détail est un fragment ajouté à la droite de la liste.   Comme ceci :

 

LivreListActivity.java 

Activity_livre_twopane.xml  contient

·       Comme ci avant le fragment LivreListFragment.java (sans xml)

·       Un container identifié @+ id/livre_détail_container, qui accueillera un fragment LivreDetailFragment.java àfragment_livre_detail.xml

 

A chaque changement de sélection le fragment est recréé et ajouté au livre_détail_container

 

 

Exercice  Androïd 016

Reprendre l’exercice 15 mais tenir compte de l’orientation de l’écran

 


 

13.        Utiliser des images

 

13.1.             Images statiques

 

Utiliser des images statiques est simple :

 

Dans le layout :

 

<ImageView

        android:id="@+id/imgAndro"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:src="@drawable/ic_launcher" />

   

     <ImageView

         android:id="@+id/imgCouleur"

         android:layout_width="wrap_content"

         android:layout_height="wrap_content"

         android:src="@drawable/couleur" />

 

src indique où se situe l’image, ici dans le répertoire res\drawable.

Noter qu’il y a plusieurs répertoires, vous pouvez fournir des images adaptées à chaque écran.

 

Ic_Launcher est l’icône de l’appli, elle est fournie par défaut.

Couleur est une image personnelle, notez qu’elle doit être fournie au format png

 

Exercice Android017

Afficher votre image favorite

13.2.             Images téléchargées

 

Du point de vue layout, il suffit de la déclarer :

 

<ImageView

          android:id="@+id/imgChoupette"

          android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          />

 

Dans l’activité :

1.     Déclarer l’url de limage

private static String url="http://www.garraud.eu/choupette.JPG";

 

      

2.     Déclarer l’image

private ImageView bmImage//l'image à renseigner

 

3.     et dans onCreate bien sur

bmImage = (ImageView) findViewById(R.id.imgChoupette);

Pour utiliser internet, n’oubliez pas de demander la permission internet pour votre appli en ajoutant dans le manifest :

 

 

 

 

<uses-sdk

        android:minSdkVersion="15"

        android:targetSdkVersion="15" />

   

    <uses-permission android:name="android.permission.INTERNET" />

 

    <application

 

Pour télécharger une image, il faudrait coder :

 

//synchrone ne fonctionne pas!

                 InputStream in = new java.net.URL(url).openStream();

                 Bitmap img = BitmapFactory.decodeStream(in);

                 this.bmImage.setImageBitmap(img);

 

 

Cependant cela ne fonctionne pas

13.3.             Charger une image en mode asynchrone

 

Le téléchargement en mode synchrone demander un délai ; de plus dans un contexte de téléphonie mobile (3G), il est hasardeux. Pour ces raisons il est souhaitable de ne pas bloquer l’interface opérateur (UI) pendant ce temps, et d’effectuer ces taches dans un thread séparé.

 

Depuis le SDK 11( android honeycomb 3.2),  c’est obligatoire, le non respect de cette règle lèverait une exception :  NetworkOnMainThreadException

 

13.4.             La classe AsyncTask

 

Pour vous éviter de programmer ces threads à la main le sdk Androïd propose une classe outils : AsyncTask. Sa mise en œuvre mérite quelques explications :

 

13.4.1.                    Coder la classe

 

Vous devez étendre la classe, de cette manière

 

private class DownloadFilesTask extends AsyncTask<T1, T2, T3>

 

AsyncTask est une classe générique, c'est-à-dire une classe dont le type de certaines données membres n’est défini qu’à l’instanciation ou à la dérivation.

 

  1. T1(Params) est le type du paramètre nécessaire à l’exécution de la tache en arrière plan. En général ce sera des String ou des java.net.URL

 

  1. T2 (Progress) Est le type qui permet de quantifier l’avancement du travail, en général un entier.

 

  1. T3 (Result) est le type du résultat du travail.

 

Ces notions vont se préciser plus loin.

 

Vous pouvez redéfinir le constructeur et surcharger 4 méthodes :

 

  1. onPreExecute(). Cette méthode s’exécute dans le thread appelant (UI). Elle permet d’initialiser l’interface au début de l’action, elle est facultative.

 

  1. Result doInBackground(Params…) Cette méthode s’exécute dans un thread séparé. Elle effectue le travail réseau, et retourne un objet de type Résult. Pour informer l’UI de l’avancement elle peut appeler régulièrement publishProgress(Progress…), ceci est facultatif.

 

  1. onProgressUpdate(Progress…) Cette méthode relaie dans le thread UI un appel à publishProgress.  Elle est facultative.

 

 

  1. onPostExecute(Result) Cette méthode s’exécute dans le thread UI, elle récupère le résultat de doInBackground et met à jour le visuel.

 

 

Bien noter que seule la méthode doInBackground s’exécute dans un thread séparé.

 

NB le symbole « Params . ». indique que ce paramètre est au choix un scalaire ou un tableau.

 

Vous pouvez redéfinir le constructeur, ceci par exemple pour récupérer un pointeur sur des éléments de l’UI.

 

13.4.2.                    Utiliser la classe

 

Depuis l’activité ou le segment utilisateur :

 

// Instancier un objet de la classe : 

DownloadFilesTask   laTache = new DownloadFilesTask() ;

 

// Appeler la méthode execute :

laTache.execute(url) ;


 

 

13.5.             Utiliser Async Task pour récupérer l’image.

 

Si on espère réutiliser la classe asynchrone, on peut alors programmer une classe externe. Voici comment on pourrait faire dans le cas d’une image à récupérer.

 

Prévoir donc une classe :

 

//pour télécharger une image de maniére asynchrone

public class DownloadImage extends AsyncTask<String, Void, Result>

 

Mais auparavant,  il faut songer que nous devrons retourner soit l’image soit un message d’erreur. Il est donc judicieux de prévoir une classe Result, par exemple :

 

public class Result

{

       private Bitmap img=null;

       private String err=null;

      

       public Result(Bitmap b)

       {

             this.img=b;

       }

       public Result(String e)

       {

             this.err=e;

       }

}//fin classe Result

 

Retournons à notre class DownloadImage, il n’y  faut rien gérer de l’affichage, mais on contraire renvoyer vers l’activité ou le fragment, on programmera donc dans l’activité une méthode affiche(Result r). Pour éviter tout mauvais usage, définissons une interface :

 

       public interface Affichable

       {

             public void affiche(Result r);

       }

 

L’activité devra donc implémenter cette interface.

 

public class MainActivity extends Activity implements DownloadImage.Affichable.

 

Pour pouvoir appeler la méthode affiche la classe DownloadImage devra possèder un pointeur vers l’activité. Nous utiliserons le constructeur à cette fin :


 

 

public class DownloadImage extends AsyncTask<String, Void, Result>

{

       private Affichable laVue;        //la vue qui nous appelle

      

       //interface interne

       public interface Affichable

       {

             public void affiche(Result r);

       }

 

    //constructeur

    public DownloadImage(Affichable v)

    {

       super();

       this.laVue=v;

    }//fin constructeur

 

Noter que par notre définition d’interface nous ne préjugeons pas du type de demandeur activity ou fragment ou view.

 

La suite est classique, voici la méthode doInBackGround :

 

  protected Result doInBackground(String... urls)

    {

        String urldisplay = urls[0];

        Bitmap img = null;

        try

        {

            InputStream in = new java.net.URL(urldisplay).openStream();

            img = BitmapFactory.decodeStream(in);

            return (new Result(img));

        }

        catch (Exception e)

        {

            return (new Result(e.getMessage()));

        }

    }//fin do In Background

 

Et la méthode onPostExecute

 

protected void onPostExecute(Result result)

    {

       this.laVue.affiche(result);

    }//fin post execute


 

 

Et dans l’activité :

 

public class MainActivity extends Activity implements DownloadImage.Affichable

{

       private static String url="http://www.garraud.eu/choupette.JPG";

 

       private ImageView bmImage//l'image à renseigner

      private TextView txtErreur; //zone pour un éventuel message d erreur

 

 

       @Override

       protected void onCreate(Bundle savedInstanceState)

       {

             super.onCreate(savedInstanceState);

             setContentView(R.layout.activity_main);

            

             //Récupérer les identifiants des objets visuels

             bmImage = (ImageView) findViewById(R.id.imgChoupette);

             txtErreur = (TextView) findViewById(R.id.txtResult);

             txtErreur.setText("Creating");

            

        //renseigner l'image

             try

             {

             //asynchrone

             DownloadImage dImg= new DownloadImage(this);

             dImg.execute(url);

             this.txtErreur.setText("OK asynchrone parti");

             }

             catch (Exception e)

             {

                this.txtErreur.setText(e.getMessage());

             }     

       }// fin onCreate

      

       @Override

       public void affiche(Result result)

       {

              if (result.getImg()!=null)

                    this.bmImage.setImageBitmap(result.getImg());

                    this.txtErreur.setText("image bien téléchargée");

               if (result.getErr()!=null)

                    this.txtErreur.setText(result.getErr());     

       }//fin affiche result

}//fin activity

 

 

Dernier conseil : Dans un projet réel, il faudra renommer judicieusement Result, Affichable, affiche etc ..

 

 

Exercice Android018

Trouver sur le web une image qui vous plait

Télécharger depuis votre application et afficher.

 


 

 

 

14.        Les services Web.

 

Pour utiliser des web services, n’oubliez pas de demander la permission internet pour votre appli en ajoutant dans le manifest :

 

<uses-sdk

        android:minSdkVersion="15"

        android:targetSdkVersion="15" />

   

    <uses-permission android:name="android.permission.INTERNET" />

 

L’utilisation des services web est vitale dans la réalisation d’applications Androïd, en effet vous utiliserez les services web, chaque fois que vous devrez obtenir des informations depuis un serveur.

 

Vous devrez maîtriser plusieurs techniques :

·       Ecrire un service Web Rest ou Soap en Dot net, java voir php.

·       Savoir appeler le service et récupérer la réponse, et cela dans le cadre des services Rest ou dans le cadre des services Soap

·       Savoir gérer l’appel de manière asynchrone, comme ci-dessus pour les images.

·       Savoir décoder une réponse Rest ou Soap.

 

15.        Service web rest

 

Voici quelques références que vous pourrez consulter.

 

http://stackoverflow.com/questions/3505930/make-an-http-request-with-android

 

As of Honeycomb (SDK 11) the asynchronous approach is the way to go.

A NetworkOnMainThreadException gets thrown when you try to run an HTTP request from the main thread.

 

http://www.tutos-android.com/asynctask-android-traitement-asynchrone-background

 

 

 

 

http://www.techrepublic.com/blog/app-builder/calling-restful-services-from-your-android-app/1076

 

 

http://developer.android.com/reference/java/net/HttpURLConnection.html

 

 

http://a-renouard.developpez.com/tutoriels/android/realiser-navigateur-web/

 

 

 

 

15.1.             Envoyer une requête Rest

 

Il faut d’abord définir l’URL, pour dot net, ce serait quelque chose de ce genre :

 

//L'url pour appeler le service Web Rest

 

private static String URL = "http://www.asp.garraud.eu/webservice/StockWatcherRest.aspx?q=1";

 

 

Le code de communication ressemble à celui d’ajax, mais il est écrit en pur java :

 

private String CallWSrest(String URL)

{

 

//transformer l'URL en URI

       URI monUri=new URI(URL); 

//construire la requête

       HttpClient httpclient = new DefaultHttpClient();

//Appeler le service

       HttpResponse response = httpclient.execute(new HttpGet(monUri));

 

//Récuperer la réponse

StatusLine statusLine = response.getStatusLine();

       if(statusLine.getStatusCode() == HttpStatus.SC_OK)

       {

              //Analyser la réponse

              ByteArrayOutputStream out = new ByteArrayOutputStream();

              response.getEntity().writeTo(out);

              out.close();

              String responseString = out.toString();

              return responseString;

       }

else

       {

             //Anyway, Closes the connection.

             response.getEntity().getContent().close();

             return statusLine.getReasonPhrase();

       }

}

 

N’oubliez pas de gérer les exceptions, plus que probable dans un tel contexte.

 

Intégrer ce code dans une classe dérivant de AsyncTask<String, String, String>

Afin de permettre l’exécution asynchrone.


 

 

15.2.             Décoder une réponse Rest, JSON

 

Dans les cas les plus simples vous recevrez une simple chaîne. Dans les cas usuels vous recevrez des objets codés au format JSON.

 

Pour parser une réponse Json il existe une bibliothèque Android

 

http://www.androidcompetencycenter.com/2009/10/json-parsing-in-android/

 

http://stackoverflow.com/questions/9605913/how-to-parse-json-in-android

 

 

http://www.androidhive.info/2012/01/android-json-parsing-tutorial/

 

 

Voici un exemple de mise en œuvre :

 

JSONArray jtab= new JSONArray(s);

 

                    JSONObject jObject= jtab.getJSONObject(0);

                   

                    this.txtSymbol.setText(jObject.getString("symbol"));

                    this.txtPrice.setText(jObject.getString("price"));

                    this.txtChange.setText(jObject.getString("change"));

 

 

Comme vous pouvez le constater, c’est la classe JSONObject qui fait tout le travail, le constructeur transforme la chaine s en un tableau d’objet.

 

 

Exercice Androïd019

Créer un service web Rest (avec dot net ou jsp au choix) retournant un stagiaire (nom,prenom) au format REST

Dans une application androïd appeler ce service web et afficher le stagiaire.

 

 

Dans les applications Androïd, on préfère généralement les services REST


 

 

16.        Service web soap

 

Vous pouvez consulter ces articles :

 

http://dsilvera.developpez.com/tutoriels/android/utilisation-web-service-soap-sous-android/

 

http://michel-dirix.developpez.com/tutoriels/android/android-et-webservices/

 

http://www.c-sharpcorner.com/UploadFile/88b6e5/how-to-call-web-service-in-android-using-soap/

 

 

L’usage de soap pour Androïd n’est pas bien supporté. Vous devrez utiliser la bibliothèque ksoap2 : http://code.google.com/p/ksoap2-android/

 

A cet effet, il faut l’inclure dans le path du projet Eclipse

 

Ici je crée une bibli SOAP dans laquelle j’inclus le jar ad hoc.

 


 

Puis je l’inclus dans le path. (On aurait pu inclure directement le jar.)

 

 

 

Ceci permet de compiler, mais suppose que la bibliothèque est dans la cible.

Comme ce n’est pas le cas, il faut également demander l’inclusion de la bibliothèque dans l’exécutable :

 

 

 


 

16.1.             Appeler un service SOAP

 

Vous devrez ajouter des imports

 

import org.ksoap2.SoapEnvelope;

import org.ksoap2.serialization.SoapObject;

import org.ksoap2.serialization.SoapSerializationEnvelope;

import org.ksoap2.transport.HttpTransportSE;

 

Vous devez définir quelques paramètres (à modifier pour utiliser votre service):

 

private static String NAMESPACE = "http://garraud.eu/";

       private static String ACTION_HELLO="http://garraud.eu/HelloWorld";

       private static String METHOD_HELLO ="HelloWorld";

private static String URL = "http://asp.garraud.eu/webservice/ServiceCatalogue.asmx?WSDL";

 

Et voici l’appel proprement dit:

 

private ResultWS callWSsoap()

{

SoapObject request = new SoapObject(NAMESPACE, METHOD_HELLO);

 

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

 

envelope.setOutputSoapObject(request);

envelope.dotNet = true;

                                                      

HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

 

//this is the actual part that will call the webservice

androidHttpTransport.call(ACTION_HELLO, envelope);

SoapObject soapResult = (SoapObject)envelope.bodyIn;

 

if(soapResult!=null)

       return (new ResultWS(soapResult) );  

else

       return (new ResultWS("pas de réponse"));

}//fin callWSsoap

 

J’ai prévu une classe ResultWS, pour transmettre résultat ou erreur.

 

private class ResultWS

       {

             private SoapObject res;

             private String erreur;

            

             //Prévoir get et set

 

             //les constructeurs.

             public ResultWS(SoapObject s)

             {

                    this.setRes(s);

             }

             public ResultWS(String r)

             {

                    this.setErreur(r);

             }

       }//fin ResultWS

 

16.2.             Analyser une réponse Soap.

 

Dans un premier temps vous pourrez vous contenter d’appeler la méthode toString() sur la réponse soapResult.

 

soapResult.toString();

 

Pour analyser membre à membre, utiliser la bibliothèque SOAP ainsi :

 

soapResult.getPropertyAsString("nom");

 

 

 

Pour des cas complexes vous pouvez vous inspirer de cet exemple, à vérifier.

 

 

//Recopier le résultat dans un tableau de Stagiaire.

 

ArrayList<Stagiaire> stagiaires = null;
int totalCount = soapobject.getPropertyCount();
if (totalCount > 0 )

{
    stagiaires
= new ArrayList<Stagiaire>();
   
for (int detailCount = 0; detailCount < totalCount; detailCount++)

    {
      
SoapObject stagiaireSoap = (SoapObject)soapobject.getProperty(detailCount);
      
Stagiaire stagiaire = new Stagiaire();
      
stagiaire.idNumber = stagiaireSoap.getProperty("nom").toString();
      
stagiaire.quantity = stagiaireSoap.getProperty("prenom").toString();

       stagiaires
.add(stagiaire);
     
}
}

 

Exercice Androïd020

Refaire l’exercice 15 en utilisant SOAP