Si vous me suivez sur GitHub, vous avez pu constater que depuis deux semaines, je m'amuse un peu en Java avec Android. Le développement d'applications Android plutôt intuitif si vous avez quelques bases en Java (pour ma part, mes bases remontent à plus de 3 ans en arrière. Comme quoi c'est vraiment intuitif). Dans cet article, nous allons voir les bases du développement d'applications Android en prenant comme exemple l'application qui m'a permis à moi, de me familiariser avec : translator.
Le fonctionnement de cette application est très simple. Vous entrez la langue d'entrée, la langue de sortie, la chaine à traduire. Et, en utilisant Google Translate, l'application va traduire cette chaine.
Installation du SDK
Afin de pouvoir tester correctement votre application, il existe un émulateur Android permettant de simuler un téléphone et ainsi d'exécuter votre application. Bien évidemment ce n'est qu'un émulateur. Vous ne pourrez pas réellement passer des appels. En revanche cela vous permettra de tester efficacement votre application.
Vous pouvez le télécharger depuis la documentation développeurs d'Android en fonction de votre système d'exploitation.
Génération du projet
Parce que nous n'utilisons pas Eclipse, nous perdons de nombreux raccourcis apportés par l'IDE. Mais cette non utilisation est un choix. Ne nous restreignons pas à un IDE et développons directement avec notre éditeur favori !
Nous allons d'abord devoir générer un nouveau projet. Android propose une commande console pour cela : android create project.
android create project \
-t <target_ID> \
-n <your_project_name> \
-p /path/to/your/project \
-a <your_activity_name> \
-k <your_package_namespace>
Plusieurs options sont requises.
- -t target : Il s'agit de la version de la plateforme Android que nous allons utiliser (ici Android 2.1). Pour obtenir la liste de toutes les plateformes disponibles, entrez androit list targets.
- -n name : Le nom que vous donnez à votre projet
- -p path : Le chemin dans lequel le nouveau projet sera créé
- -a activity : Le nom de la fenêtre qui sera ouverte par défaut lorsque l'application sera lancée.
- -k package : Le nom du package qui sera créé. Il doit suivre la convention de nommage des packages en java.
Créons notre nouveau projet que nous allons nommer "Translator". Ce projet nous permettra de traduire une chaine de caractères d'une langue à l'autre grâce à Google Translate.
android create project \
-t 1 \
-n Main \
-p ~/projects/translator \
-a Translator \
-k com.android.translator
Cela va générer de multiples fichiers dans votre nouveau projet Android
Le java pur : traduire une chaine avec Google Translate
Dans cet exemple, nous allons développer une application simple. Le principe est le suivant : nous choisissons deux langues. Une en entrée et une en sortie.
Puis nous saisissons du texte. Et notre texte sera traduit d'une langue à l'autre.
Le langage de base pour toute application Android est le java. Dans cet article, je vais considérer que vous avez déjà des bases en Java. Si ce n'est pas le cas, vous trouverez de nombreux articles sur programmez.com.
Pour cette application nous allons utiliser une librairie open source et permettant de faire des appels à Google Translate : Google API Translate Java. Vous devez tout d'abord include cette librairie dans votre projet nouvellement créé. Téléchargez la sur Google Code (le fichier .jar) et placez la dans le dossier /libs de votre projet.
Nous allons pouvoir tout de suite coder une classe d'abstraction faisant appel à cette librairie
package com.android.translator;
import com.google.api.translate.Language;
import com.google.api.translate.Translate;</p>
public class Translator {
/*
* Takes the string to translate and does the work
*/
public static String translate(String text, Language lang_from, Language lang_to) throws Exception {
Translate.setHttpReferrer("http//www.dmathieu.com");
String translatedText = Translate.execute(text, lang_from, lang_to);
return translatedText;
}
}
Que faisons-nous ici ?
package com.android.translator;
import com.google.api.translate.Language;
import com.google.api.translate.Translate;
Nous définissons le package courant et nous incluons la librarie précédemment téléchargée qui fera la liaison avec Google Translate.
Translate.setHttpReferrer("http//www.dmathieu.com");
String translatedText = Translate.execute(text, lang_from, lang_to);
Ainsi nous pouvons faire appel à Translator.translate afin de traduire une chaine d'une langue vers l'autre.
Translator.translate("Hello World", Language.ENGLISH, Language.FRENCH);
Placez ce document dans un fichier que nous nommerons Translator.java dans le dossier src/com/android/translator. Et ... C'est tout pour le moment. Nous allons maintenant pouvoir nous attaquer au réel développement de l'application et de son interface.
Création de l'interface Android
Nous allons maintenant créer l'interface de notre application, contenant deux listes déroulantes, un champ de texte, un bouton et notre chaine traduite. L'interface de votre application se développe en XML.
Voici le XML permettant d'obtenir le rendu de la capture d'écran plus haut, situé dans res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<Spinner
android:id="@+id/languages_from"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="@string/from_languages_prompt" />
<Spinner
android:id="@+id/languages_to"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="@string/to_languages_prompt" />
<EditText
android:id="@+id/text_to_translate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/editbox_background"
android:prompt="@string/text_to_translate" />
<Button
android:id="@+id/translate_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="@string/translate_button" />
<TextView
android:id="@+id/translated_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Qu'est-ce qui se passe ?
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
</LineraLayout
Nous définissons le cadre de notre fenêtre. LinearLayout nous permet de définir une fenêtre contenant divers éléments qui seront positionnés les uns à la suite des autres, soit horizontalement soit verticalement.
Il existe, en plus des LinearLayout, divers types d'éléments permettant de créer des cadres dans lequels vous pourrez placer les éléments de votre interface :
- AbsoluteLayout : Un layout permettant de placer ses éléments de manière absolue, en spécifiant leurs coordonnées x/y.
- FrameLayout : Un layout permettant d'afficher un et un seul élément. Si plusieurs éléments sont présent, le dernier sera au dessus. La taille du layout sera celle du plus grand des enfants.
- RelativeLayout : Un layout dans lequel chacun des éléments sont positionnés à la suite l'un de l'autre.
- TableLayout : Un layout permettant de positionner ses enfants en lignes et colonnes.
Puis à l'intérieur de ce layout nous avons divers éléments.
<Spinner
android:id="@+id/languages_from"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:prompt="@string/from_languages_prompt" />
L'élément Spinner permet de définir une liste déroulante. Nous en avons donc ici deux, un pour le langage en entrée et un pour le langage en sortie.
<EditText
android:id="@+id/text_to_translate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/editbox_background"
android:prompt="@string/text_to_translate" />
L'élément EditText est un champ textuel à remplir. L'utilisateur pourra y placer le contenu de son choix. Ici, nous y rentreront la phrase ou les mots à traduire.
<Button
android:id="@+id/translate_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="@string/translate_button" />
Afin de signifier à l'application que nous avons fini de taper la phrase et que nous sommes prêt à en obtenir la traduction, nous ajoutons ici un bouton.
<TextView
android:id="@+id/translated_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
Enfin nous ajoutons un champ de texte non éditable qui contiendra la chaine de caractères traduite.
Chaines de traduction
Lorsque, tout à l'heure, nous exécuterons l'application que nous sommes en train de développer, vous pourrez cliquer sur le spinner et choisir une langue.
Alors vous verrez la capture d'écran de gauche. Comme vous pouvez le constater, nous avons une petite phrase explicative disant "Choose a language to translate from".
android:prompt="@string/from_languages_prompt"
Notre fichier ressemble à ceci :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Translator</string></p>
<string name="from_languages_prompt">Choose a language to translate from</string>
<string name="to_languages_prompt">Choose a language to translate to</string>
<string name="text_to_translate">The text you wish to translate</string>
<string name="translate_button">Translate!</string>
</resources>
Vous pouvez constater que dans main.xml, nous faisons appel à @strings/xxx. Vous l'aurez compris, @strings correspond au nom du fichier. Vous pouvez donc sans aucun problème diviser les chaines de caractères de vos grosses applications en de multiples fichiers.
Si nous désirons ajouter une traduction en Français à notre application, il nous suffira alors de créer res/values-fr/strings.xml Qui contient, pour notre application :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Translator</string></p>
<string name="from_languages_prompt">Langue d'origine</string>
<string name="to_languages_prompt">Langue de destination</string>
<string name="text_to_translate">Texte à traduire</string>
<string name="translate_button">Traduire!</string>
</resources>
Remplissage des Spinner
Le contenu de nos listes déroulantes sera la liste de toutes les langues que Google Translate peut traduire. Nous allons remplir cela dynamiquement en fonction de toutes les langues disponibles dans la librairie Google Translate que nous utilisons. Cette liste est un enum Java : un objet contenant une liste d'éléments.
Rappelez vous, lorsque vous avez créé votre projet, vous avez défini le nom d'une classe "Activity", qui caractérise la fenêtre par défaut. Si vous avez suivi cet article à la lettre, votre Activity doit se nommer Main. Vous avez donc un fichier src/com/android/translator/Main.java. Ouvrons le.
Il contient une activity vide, permettant uniquement de charger la fenêtre.
package com.android.translator;</p>
<p>import android.app.Activity;
import android.os.Bundle;</p>
<p>public class HelloAndroid extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
C'est la méthode onCreate qui nous intéresse. Elle est appelée avec un paramètre savedInstanceState qui est le status précédent de l'application. Nous commençons par faire un appel à cette même méthode onCreate de la classe parente, permettant ainsi de charger l'environnement requis par Android pour l'application.
La ligne suivante est plus intéressante.
setContentView(R.layout.main);
R.layout.main est un entier (objet Integer). Chaque élément de votre interface (les éléments XML définis précédemment) est défini en Java par un entier. Vous pouvez donc retrouver chacun d'eux grâce à cet entier. Et vu qu'une constante contenant ce même entier est définie à chaque fois, vous pouvez le retrouver encore plus facilement ! Ici, R.layour.main caractérise le fichier layout/main.xml. Vous pouvez donc définir l'interface qui sera affichée par votre activity.
Vu que nous allons devoir ajouter du contenu à l'intérieur de nos deux Spinner, nous allons donc devoir récupérer leur contenu. Ils sont également identifiés par un entier. Dans notre spinner, nous avons défini un attribut android:id.
android:id="@+id/languages_from"
Nous allons donc pouvoir récupérer l'identifiant de notre spinner avec la constante R.id.languages_from
Spinner language_from = (Spinner) findViewById(R.id.languages_from)
Spinner language_to = (Spinner) findViewById(R.id.languages_to)
Nous allons pour cela devoir créer un objet de type ArrayAdapter, qui sera un tableau de chaines de caractère, chaque élément représentant une entrée de la liste déroulante.
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Pour ajouter un élément à un adapter, nous avons juste à utiliser la méthode add.
adapter.add("Ma Valeur");
Ici, toutes nos valeurs sont contenues dans un enum de la librairie Google Translate. Nous devons parcourir tous ces éléments et ajouter toutes les clés.
for (Language l : Language.values()) {
adapter.add(l.name());
}
Super ! Une dernière petite chose pourtant. Notre adapter a été créé mais n'a été assigné nulle part. Il faut donc assigner les valeurs à nos deux spinners.
languages_from.setAdapter(adapter);
languages_to.setAdapter(adapter);
Ce qui nous donne, au final, pour définir le contenu de nous nos spinners :
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);</p>
Spinner language_from = (Spinner) findViewById(R.id.languages_from)
Spinner language_to = (Spinner) findViewById(R.id.languages_to)</p>
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);</p>
for (Language l : Language.values()) {
adapter.add(l.name());
}</p>
languages_from.setAdapter(adapter);
languages_to.setAdapter(adapter);
}
Pas trop perdu ? :)
Evènements : clic sur le bouton
Notre application commence à ressembler à quelque chose. Mais n'est pas encore utilisable. Pour cela, il nous faudrait en effet encore pouvoir traduire la phrase entrée dans le champs de texte. Allons y !
Nous désirons effectuer cette traduction lorsque l'utilisateur clique sur le bouton "Traduire !". Pour cela nous devons ajouter un listener de clic sur ce bouton. Une fonction qui sera exécutée à chaque clic.
A la suite du code précédent, plaçons notre listener :
findViewById(R.id.translate_button).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String text = ((EditText) findViewById(R.id.text_to_translate)).getText().toString();</p>
try {
Language lang_from = Translator.getLanguageString((Spinner) findViewById(R.id.languages_from));
Language lang_to = Translator.getLanguageString((Spinner) findViewById(R.id.languages_to));
String translatedText = Translator.translate(text, lang_from, lang_to);
((TextView) findViewById(R.id.translated_text)).setText(translatedText);
} catch(Exception e) {
((TextView) findViewById(R.id.translated_text)).setText(e.toString());
}
}
});
Que faisons nous ici ?
findViewById(R.id.translate_button)
String text = ((EditText) findViewById(R.id.text_to_translate)).getText().toString();
try {
****
} catch(Exception e) {
((TextView) findViewById(R.id.translated_text)).setText(e.toString());
}
Si, pour une raison quelconque, une erreur est survenue lors de la traduction de l'application, nous désirons pouvoir afficher cette erreur tout de même. Ainsi, si la connexion internet n'est pas disponible, il n'est pas possible de traduire la chaine. Une exception serait alors soulevée. Avec le try/catch, nous interceptons cette exception et affichons son contenu dans le champs de texte. Si nous n'avions pas ce try/catch, l'application se fermerait avec un message incompréhensible à chaque erreur.
Language lang_from = Translator.getLanguageString((Spinner) findViewById(R.id.languages_from));
Language lang_to = Translator.getLanguageString((Spinner) findViewById(R.id.languages_to));
Nous récupérons ici les deux langues sélectionnées en entrée et en sortie dans les deux spinners. La méthode Translator.getLanguageString doit être définie dans src/com/android/translator. Elle contient le code suivant :
public static Language getLanguageString(Spinner spinner) throws Exception {
String lang = spinner.getSelectedItem().toString();</p>
for (Language l : Language.values()) {
if (l.name() == lang) {
return l;
}
}
throw new Exception("Unknown language provided : " + lang);
}
Avec la méthode getSelectedItem(), nous récupérons la langue sélectionnée dans le spinner. Cependant la librairie Google Translate requiert que nous lui transmettions un objet de type Language. Pas une string comme retournée par le spinner. Nous parcourons donc toutes les langues disponibles jusqu'à trouver la bonne et la retourner. Si aucune langue n'est la bonne, nous soulevons une exception (qui sera alors prise en charge par le try/catch vu plus haut).
Continuons dans notre action sur le clic sur le bouton.
String translatedText = Translator.translate(text, lang_from, lang_to);
((TextView) findViewById(R.id.translated_text)).setText(translatedText);
Conclusion
Désolé pour le (trop) long article ! Notre application est maintenant développée. Il ne nous reste maintenant plus qu'à l'installer sur le SDK afin de la tester, puis sur notre téléphone afin de l'utiliser. Pour tester et installer votre application sur le SDK et un vrai téléphone, vous pouvez référer à la suite de cet article : Déployer une application Android.


Commentaires
Grand merci pour ce tutorial !
Article très bien rédigé.
Faudra que je me lance dans le dev sur la plateforme de mon téléphone, un jour.
Bonjour,
Merci pour ce tuto très bien fait, j'ai appris pas mal de chose. Je suis un dev java et je me suis lancé il y a 2 jours dans le développement Android.
J'ai un petit souci dans mon application, quand j'essaye de remplir mon spinner, le programme plante.
Voila mon code:
spin = (Spinner)findViewById(R.id.spin_question);
Si quelqu'un a une idée, Merci d'avances,
Quelle est l'erreur ?
Autant pour moi! J'ai du oublier quelque chose, j'ai tout retapé du début et ça fonctionne parfaitement. Désolé et merci encore pour le super tuto, je galérais depuis 1h sur les Spinner!
A+
:) La suite (installation/déploiement) arrive très très bientôt.
ça donne envie de se mettre à java :) ..voir la programmation objet tout court un jour peut être :)
Bonjour, d'abord merci bien pour ce tuto très bien détaillé. que j'ai suivi à la lettre mais je me suis bloquée dès le début à l'étape de création de la classe d'abstraction faisant appel à la librairie google api translate java qe j'ai placé sous le dossier "src" de mon projet car moi j'utilise eclipse comme éditeur et le dossier /libs ne figure pas ds mon projet ! pourtant des erreurs persiste tjrs :
-The import com.google.api.translate.Translate cannot be resolved
merci de m'aider sur ce point :(
Bonjour,
Merci, pour ce tuto très bien expliqué, cependant j'ai une erreur au moment du lancement. Lors de la validation j'ai l'erreur suivante :
java.lang.Exception:[google-api-translate-java] Error retrieving translation
Voila, et je n'est également pas de langue pré défini, donc dans le premier Spinner il y a écrit AUTO_DETECT
Si vous avez les réponses à ces problèmes, je suis preneur!
Coridalement Sylveling!
bonjour, moi aussi j'ai pas de langues predefinies ca affiche autodetect s il es possible de regler ça se serait mieux, et aussi ca m'affiche des caractères bizarres lorsque je fais une traduction vers l'arabe, le chinoirs ou encore le japonais... j'aimerai savoir si on peut regler celà.
bonjour, je cherche un exemple de source me permettant d'alimenter un spinner à partir d'une table sqlite et de recuperer l'identifiant de la selection dans le spinner exemple une table fournisseur avec id_fournisseur nom_fournisseur je veux afficher les noms des fournisseurs dans le spinner et lorsque je selectionne un fournisseur, recuperer son id_fournisseur comment faire? merci d'avance
Grand merci pour ce petit tuto, j'avais un petit problème avec mon ArrayAdapter, c'est réglé grâce à vous ;)