Votre première application Android (mais en mieux)

Vous savez maintenant créer une application basique avec Android. Seulement sachez le, si elle est fonctionnelle, elle est codée avec la bien nommée méthode Rache. Bien que nous n’allons pas nous lancer dans l’élaboration d’un programme digne du Developper Challenge, nous améliorerons ce premier jet pour en faire une base de code que vous pourrez utiliser comme exemple pour la suite.

En résumé, la fois précédente, c’était pour comprendre, mais dans la vrai vie (celle avec des chats, l’impôt sur le revenu, et Francis Lalanne) il ne faudra jamais faire comme ça : nous allons tout de suite voire ce qui ne va pas.

Ce que vous allez apprendre :

  • Comment utiliser les chaînes de caractères par référence.
  • Comment coder les événements de manière à les découpler du code principal.

Les pré requis :

  • Avoir fait le tuto précédent et surtout bien compris la partie de gestion des événements.
  • Connaître le formatage des chaînes en Java.
  • Avoir des notions sur les références et l’i18n est un plus.

Temps nécessaire : 30 minutes. Un petit tuto cool, pour se reposer.

Remplacer toutes les chaînes de caractères par des références

Dans nos premiers codes, nous avons écris directement les chaînes de caractères là où nous en avions besoin. C’est mal. Presque autant que croiser les effluves.

En effet il existe un mécanisme dans Android qui permet de stocker toutes ces chaînes au même endroit, comme pour les vues XML, et ensuite de les appeler comme n’importe quelle ressource du dossier RES.
Les avantages :

  • Quand on doit modifier du texte, on sait toujours où chercher.
  • Quand on a une chaine répétée plusieurs fois, on l’écrit une seule fois. Si elle change on la change une seule fois
  • Et surtout, il est très facile de rajouter une nouvelle langue par la suite si vous souhaitez traduire le logiciel.

Nous allons donc voir comment faire, et à partir de maintenant vous n’utiliserez plus que cette méthode, ou votre IP sera bannie d’évidence.net.

Le fichier strings.xml

Dans le dossier res/values se trouve un fichier, strings.xml. Le nom n’a pas d’importance, mais c’est une convention plutôt agréable à suivre. Ouvrez le depuis Eclipse. Comme pour le fichier main.xml, il y a deux onglets, prenez le dernier de droite pour voir directement le code XML.

Vous devriez obtenir ceci :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, HelloWorld!</string>
    <string name="app_name">HelloWorld</string>
</resources>

Toutes les chaînes sont écrites les unes à la suite des autres dans le noeud « resources », qui lui est unique. La syntaxe est la suivante :

<string name="un_identifiant_unique_pour_lachaine">
La chaîne de la longueur que vous voulez, même 100 lignes. C'est le l'UTF-8 alors faîtes vous plaisir, utilisez directement les accents.
</string>

Reprenez le fichier res/layout/main.xml. Rappelez vous que nous avions une vue texte pour l’invite de saisie :

<TextView  
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text="Entrez votre nom :"
/>

Nous allons déplacer « Entrez votre nom : » de main.xml à strings.xml. D’abord, dans strings.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- On supprime la string que l'on utilise pas et on rajoute notre phrase avec l'id « enter_name »-->
      <string name="app_name">HelloWorld</string>
	<string name="enter_name">Entrez votre nom</string>
</resources>

Certains y verrons une analogie avec GNU Gettext. L’ordre des balises « string » n’a pas d’importance. Ensuite, on référence, cette chaîne dans la vue de main.xml. La syntaxe est :

@string/identifiant_de_la_chaîne

Ce qui donne :

<TextView  
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text="@string/enter_name"
/>

On fait la même chose pour le bouton « OK ». Et profitez-en pour changer le nom de l’application, la balise « app_name ». Au final vos deux fichiers ressemblent à :

strings.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="enter_name">Entrez votre nom</string>
    <string name="ok_button">OK</string>
    <string name="app_name">Hello Toi</string>
</resources>

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"
    >
 
	<TextView  
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text="@string/enter_name"
	/>
 
	<EditText android:layout_width="fill_parent"
	          android:layout_height="wrap_content"
	          android:id="@+id/my_edit_text"
	/>
 
	<Button android:layout_width="fill_parent"
	        android:layout_height="wrap_content"
	        android:text="@string/ok_button"
	        android:id="@+id/my_button"
	/>
 
</LinearLayout>

Lancez à nouveau l’application… Il n’y à aucune différence ! Mais vous avez bien séparé les valeurs de leurs références, et votre code est plus souple et maintenable.

Changer une chaîne de caractère dynamiquement

Vous avez dû remarquer qu’il manque un petit quelque chose dans notre modification précédente. Le « Hello » du Toast est toujours en dur dans le code. Or je vous l’ai dis, c’est mal. Nous allons changer cela également.

D’abord, on rajoute le « Hello » dans le fichier XML :

<string name="hello">Hello, %s</string>

Hey, il y a un changement, le « %s » ! C’est un marqueur de formatage que nous allons utiliser pour faire apparaite le nom dynamiquement à cet endroit. Vous l’avez compris, on garde la chaîne d’un côté pour la souplesse, et les parties qui changent sont « remplies » dans le code à la volée. Tout fonctionnne exactement comme String.format() donc vous ne devriez pas être perdu, et en cas de trou de mémoire, il reste des références partout sur le Web.

Ensuite on récupère la chaîne depuis le code Java :

// ça ne change pas
String my_name = my_edit_view.getText().toString();
 
// On utilise getResources pour récupérer un accesseur sur tout
// le contenu du dossier RES. Cet accesseur permet d'utiliser la
// méthode getString qui attend un Id (la fameuse classe R...)
 
// le deuxième paramètre optionnel est ce qu'on veut insérer dans les marqueurs de formatages
 
// comme %s, ici le nom qu'on a récupéré depuis la vue de saisie.
String hello = getResources().getString(R.string.hello, my_name);
 
// on passe notre nouvelle string toute fraiche
Toast my_message = Toast.makeText(HelloWorld.this,
                              hello,
                              1);

On relance l’application. Et hop, toujours rien de changé. Mais votre code à des strings très propres maintenant. Si je puis me permettre.

Revoir la gestion des événements

La dernière fois nous avions créé l’événement à la volée dans le code pour lier le clic du bouton à l’apparition du « Hello ». Mais avec un programme plus gros, vous aurez bien plus d’événements, qui feront des choses plus complexes, et qui seront par ailleurs utilisés à plusieurs endroits en même temps, DRY oblige.

La best practice du jour, donc, est de mettre tous les événements dans un conteneur séparé. C’est ce que fait Google pour ses applications si vous regardez leur code source. Si vous ne regardez pas, faites moi confiance :-) Il y a deux manières de faire ça :

  1. Une grosse classe avec tous les événements en Inner class. Un peu comme une classe « R » “spéciale événement”. Ok pour les petits projets, mais pas folichon si il y a beaucoup d’événements complexes.
  2. Faire un package spécialisé dans les événements. Une solution très lourde au début, mais qui paye sur la longueur, et que nous allons donc privilégier.

Pour créer un package, clic droit, « New > Package »


Ensuite, on le nomme « event », et on le place dans « world.hello ».

On créé ensuite dedans une classe “OnOkButtonClickListener” qui sera notre Listener et donc implémente l’interface “OnClickListener” :

public class OnOkButtonClickListener implements OnClickListener {}

La liste des imports utiles par la suite :

import world.hello.R;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.Toast;

Mais vous pouvez bien sûr tout aussi bien utiliser Ctrl + Shift + O une fois tout le code écrit :-)

D’abord, on définit un constructeur. C’est un peu la partie ennuyeuse de ce refactoring, il faut qu’on passe un Context au Listener pour qu’il ai accès aux ressources du dossier RES. Donc on va artificiellement lui en passer un. Il se trouve qu’une Activity est un objet Context, donc tout va bien :

// une variable membre pour contenir une référence vers le context
Activity context;
 
// un contructeur public qui attend qu'on lui passe le contexte
public OnOkButtonClickListener( Activity context) {
    this.context = context;
}

Puis on réécrit la méthode onClick :

EditText my_edit_view = (EditText) findViewById(R.id.my_edit_text);

Devient :

EditText my_edit_view = (EditText) this.context.findViewById(R.id.my_edit_text);

On préfixe par this.context car un Listener n’a pas de méthode findViewById. Ensuite :

String hello = getResources().getString(R.string.hello, my_name);

Se transforme en :

String hello = this.context.getString(R.string.hello, my_name);

Plus besoin du getRessources car Activity possède une méthode qui fait office de raccourcie vers getString. De toute façon un Listener n’a pas de getString. On continue avec :

Toast my_message = Toast.makeText(HelloWorld.this,
                                                   hello,
                                                   1);

Réécrit en :

Toast my_message = Toast.makeText(this.context,
                                                   hello,
                                                   1);

Un Toast a besoin d’un Context, ça tombe bien on en a un ! Enfin, on retourne dans le code principal de la méthode onStart de HelloWorld.java, et on substitue :

OnClickListener my_listener = new OnClickListener() {
 
    public void onClick(View v) {
 
        EditText my_edit_view = (EditText) findViewById(R.id.my_edit_text);
        String my_name = my_edit_view.getText().toString();
        String hello = getResources().getString(R.string.hello, my_name);
 
        Toast my_message = Toast.makeText(HelloWorld.this,
                                                            hello,
                                                            1);
        my_message.show();
     }
};
 
Button my_button = (Button) findViewById(R.id.my_button);
my_button.setOnClickListener(my_listener);

Par :

OnOkButtonClickListener ok_button_listener = new OnOkButtonClickListener(this);
Button my_button = (Button) findViewById(R.id.my_button);
my_button.setOnClickListener(ok_button_listener);

Les imports deviennent alors :

import word.hello.event.OnOkButtonClickListener;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;

Au final, le code de l’activité principale :

package world.hello;
import word.hello.event.OnOkButtonClickListener;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
 
public class HelloWorld extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        OnOkButtonClickListener ok_button_listener = new OnOkButtonClickListener(this);
 
        Button my_button = (Button) findViewById(R.id.my_button);
        my_button.setOnClickListener(ok_button_listener);
}

Et le code de la gestion des événements :

package word.hello.event;
 
import world.hello.R;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.Toast;
 
public class OnOkButtonClickListener implements OnClickListener {
 
    Activity context;
 
    public OnOkButtonClickListener(	Activity  context) {
        this.context = context;
    }
 
    public void onClick(View v) {
 
        EditText my_edit_view = (EditText) this.context.findViewById(R.id.my_edit_text);
        String my_name = my_edit_view.getText().toString();
        String hello = this.context.getString(R.string.hello, my_name);
 
        Toast my_message = Toast.makeText(this.context,
                                                            hello,
                                                            1);
        my_message.show();
    }
};

Vous notez immédiatement plusieurs bénéfices. Le « Main » est tout de suite plus clair, il ne se charge que de la mécanique, et on comprend tout de suite le flow du programme. Ensuite la gestion des évènements est découplée. Rien ne nous empêche maintenant d’utiliser votre Listener sur un autre bouton d’une autre activité.

Lancez votre application une nouvelle fois. Toujours aucune différence ! Décidément on en aura fait des choses qui ne font rien aujourd’hui :-) Aller, pour vous montrer à quel point il est pratique d’avoir du code découplé, on va modifier l’événement pour qu’il vérifie que la zone de saisie n’est pas vide. Si elle est vide, le Toast affiche « Hello Anonyme ».

L’exercice récapitulatif

On rajoute la chaîne anonyme dans le res/values/strings.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="enter_name">Entrez votre nom</string>
    <string name="ok_button">OK</string>
    <string name="app_name">Hello Toi</string>
    <string name="hello">Hello, %s</string>
    <string name="anonymous">Anonyme</string>
</resources>

On Modifie juste le fichier d’événement, pas besoin de toucher au reste ! Ok, dans ce cas ce n’est pas un gain énorme, mais dans un gros projet, une Activity mince est une Activity bien portante. Dans le Listener, OnCLick devient :

public void onClick(View v) {
 
    EditText my_edit_view = (EditText) this.context.findViewById(R.id.my_edit_text);
 
    String my_name = my_edit_view.getText().toString();
 
    // on rajoute juste cette petite partie
    if (my_name.equals(""))
    {
        my_name = this.context.getString(R.string.anonymous);
    }
 
    String hello = this.context.getString(R.string.hello, my_name);
 
    Toast my_message = Toast.makeText(this.context,
                                                        hello,
                                                        1);
    my_message.show();
}

Et voilà :

Synthèse du code…

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"
    >
 
	<TextView  
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text="@string/enter_name"
	/>
 
	<EditText android:layout_width="fill_parent"
	          android:layout_height="wrap_content"
	          android:id="@+id/my_edit_text"
	/>
 
	<Button android:layout_width="fill_parent"
	        android:layout_height="wrap_content"
	        android:text="@string/ok_button"
	        android:id="@+id/my_button"
	/>
 
</LinearLayout>


strings.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="enter_name">Entrez votre nom</string>
    <string name="ok_button">OK</string>
    <string name="app_name">Hello Toi</string>
    <string name="hello">Hello, %s</string>
    <string name="anonymous">Anonyme</string>
</resources>


OnOkButtonClickListener.java :

package word.hello.event;
 
import world.hello.R;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.Toast;
 
public class OnOkButtonClickListener implements OnClickListener {
 
    Activity context;
 
    public OnOkButtonClickListener(	Activity  context) {
         this.context = context;
    }
 
    public void onClick(View v) {
 
        EditText my_edit_view = (EditText) this.context.findViewById(R.id.my_edit_text);
 
        String my_name = my_edit_view.getText().toString();
 
        if (my_name.equals(""))
        {
            my_name = this.context.getString(R.string.anonymous);
        }
 
        String hello = this.context.getString(R.string.hello, my_name);
 
        Toast my_message = Toast.makeText(this.context,
                                                            hello,
                                                            1);
        my_message.show();
    }
};

Et HelloWorld.java :

package world.hello;
import word.hello.event.OnOkButtonClickListener;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
 
public class HelloWorld extends Activity {
    /** Called when the activity is first created. */
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        OnOkButtonClickListener ok_button_listener = new OnOkButtonClickListener(this);
 
        Button my_button = (Button) findViewById(R.id.my_button);
        my_button.setOnClickListener(ok_button_listener);
     }
}

Parfait, vous avez maintenant des habitudes de base saines pour programmer sur Android. Bien sûr, il y a bien d’autres pratiques recommandées, un chapitre dans la documentation de Google y est même consacré. Mais nous verrons cela beaucoup plus tard. Pour le moment, nous nous focaliserons sur la mise en forme.

Le prochain tuto portera sur le placement avancé des vues et la modification de leurs attributs dans le XML et le code Java.

20 Réponses à “Votre première application Android (mais en mieux)”

  1. Matthieu Dit:

    Encore une fois très bon tutoriel.

  2. kevin Dit:

    Merci matthieu. Pour me donner une idée, quel est ton niveau en programmation Android ?

  3. E-vidence » Archive du blog » Les bases de la mise page d’une application Android Dit:

    [...] E-vidence « Votre première application Android (mais en mieux) [...]

  4. Matthieu Dit:

    Mon niveau en programmation android est débutant et je n’ai d’ailleurs pas de mobile android pour le moment.Je compte m’acheter le htc hero le mois prochain.
    Sinon j’ai déjà pas mal d’expérience en programmation mais pas en java.

  5. Profete162 Dit:

    Salut matthieu!

    Bien, comme tout le monde, un grand merci pour tes tutos excellentissimes.

    Après les lauriers, voici ma question:

    Est-il possible d’avoir plus d’infos sur la marche à suivre pour créer un deuxieme bouton?

    Intuitivement, j’ai rajouté une classe et dans le “oncreate”, j’ai ajouté ces lignes:

    OnMenuButtonClickListener menu_button_listener = new OnMenuButtonClickListener(this);
    Button my_button = (Button) findViewById(R.id.my_menu_button);
    my_button.setOnClickListener(menu_button_listener);

    OnOkButtonClickListener ok_button_listener = new OnOkButtonClickListener(this);
    my_button = (Button) findViewById(R.id.my_ok_button);
    my_button.setOnClickListener(ok_button_listener);

    Cela me semble un peu lourd, non? En tous cas, cela fonctionne, mais j’ai l’impression de sortir la grosse artillerie pour tuer une mouche. J’imagine mal créer 32 classes si je dois utiliser 32 boutons dans le prog!

    Merci à toi pour les infos.

  6. kevin Dit:

    Hello Christophe,

    Donc Matthieu, c’est un lecteur. Moi c’est Kevin. Mais enchanté quand même, et merci de ton enthousiasme.

    Effectivement, c’est très lourd à écrire. La création d’interface graphique, c’est généralement assez bourrin. Heureusement, Android propose des raccourcis pour presque tout, et les Listeners ne font pas exceptions.

    Il existe donc un attribut XML “android:onClick”, qui permet de choisir une méthode à lier directement dans la définition de la vue. Plus de détails ici :

    http://developer.android.com/reference/android/view/View.html#attr_android:onClick

    N.B : disponible uniquement pour la dernière version d’Android (Donut)

    C’est pratique si :

    - Le programme est petit.

    - Il y a beaucoup de boutons.

    - On n’a presque que des événements de type “clic”

    C’est limité car :

    - On est obligé d’utiliser une méthode du contexte. Or plus l’application devient complexe, plus on essaye de limiter au maximum le code dans l’activité principale.

    - Il n’y a pas d’attribut pour tous les événements, donc pour un spinner par example, on est obligé de définir manuellement onSelectedItem() de toute façon.

    C’est pour cela que je ne l’ai pas mis dans le tuto. En effet, au final on a toujours a écrire ce genre d’opération à la main quand le programme grandit.

    Si créer une classe à chaque fois te parait lourd, c’est normal, c’est du Java, on créer des classes à tout bout de champ. Un moyen de limiter cela et de créer une grosse classe Listener pour tous les boutons, et de la passer à tous les boutons. Cette classe décide en interne quel comportement adopter en fonction du bouton. A faire seulement si le traitement lié aux boutons n’est pas complexe.

    J’en profite pour répondre à ton mail ici car ça peut aider d’autres personnes :

    < < Salut Matthieu,

    Tout d'abord je ne sais pas comment te remercier pour tes tutos! Apres des semaines de recherches sur le net, un ami m'a conseillé ton site.

    Résultat: apres 3 heures, j'en savais plus qu'en une semaine et des centaines de tutos lus!

    J'aurais juste une petite question supplémentaire:

    J'aimerais créer un bouton pour quitter l'appli, comment le faire proprement?

    Y'a-t-il une commande toute faite?

    Un grand merci.

    >>

    Il existe une méthode qui termine l’activité en cours. Il s’agit de finish(). Il suffit alors de lier l’événement on click à la méthode this.finish().

    Par curiosité, tu travailles sur quel genre de programme ?

  7. Profete162 Dit:

    heuuu je devrais peut-être te parler par mail pour ne pas que tes commentaires deviennent un forum, tu préfères peut-être que je te contacte directement par mail.

    Je vais regrouper mes 2 questions en demandant comment faire un bouton pour quitter mon appli…

    avec ton attribut: “android:onClick”, je pensais faire:

    <Button android:layout_height=”wrap_content”
    android:layout_width=”wrap_content”
    android:id=”@+id/my_quit_button”
    android:text=”quitter”
    android:onClick=”this.finish()”

    Je suis totalement à côté de la plaque alors?

  8. kevin Dit:

    Je pense qu’il est bien de répondre ici, comme ça ceux qui rencontrent le même problème que toi auront la réponse.

    Si les commentaires deviennent un jour trop surchargés, j’ouvrirais un forum :-) Mais la communauté Android n’est pas si énorme au point de risquer un DOS…

    Alors, dans l’idée ça serait plutôt ça :

    <Button android:layout_height=”wrap_content”
    android:layout_width=”wrap_content”
    android:id=”@+id/my_quit_button”
    android:text=”quitter”
    android:onClick=”finish”
    />

    Car finish ne peut être qu’une méthode du contexte courant donc le “this” n’est pas nécessaire. On appelle pas la méthode, on la nomme, donc pas de “()” non plus.

    Mais il y a un hic (y en a toujours un, ce serait trop simple) ou plutôt deux hics :

    - La signature de la méthode doit être du genre :

    public void myMethod(View my_view);

    Donc finish() ne va pas, il faut créer une méthode dans ton activité avec cette signature (le void, et la vue en paramètre, même si tu ne l’utilise pas au final !) qui elle appelle this.finish().

    - Ça ne marche qu’avec android Donut, donc la dernière version !

    Du coup, comme je disais précédement, on améliore forcément ses qualités de dactylo quand on code pour Android ;-)

  9. Profete162 Dit:

    Bon bin je suis parti dans mes commentaires et questions!

    Première remaque:

    Le fait de déplacer un bouton qui fonctionne tres bien dans le main.xml vers un autre écran (j’ai crée ecrandeux.xml dans lequel j’ai coupé/collé mon bouton) provoque une énorme erreur et un crash de l’application

    Seconde remarque: (qui doit être liée à la premiere)

    J’ai fait un mini menu qui me permet de voyager entre mes 2 layout. Si je vais dans le second layout et que je reviens dans le main (”this.context.setContentView(R.layout.main);”) je reviens à l’écran principal, mais plus aucun bouton ne fonctionne!

    Promis, c’est ma derniere remarque et je vais arrêter de poser ainsi mes questions et te laisse te reposer quelques jours… lol

  10. kevin Dit:

    Pour la première remarque, sans voir le code, difficile de répondre. Met le code dans un pastebin ou mieux sur un repos.

    Pour le deuxième, setContentView() recharge tout le layout, depuis le début, en recréant tous les objets. Non seulement c’est très gourmand en ressources, mais en plus ça fait évidement sauté tous les Listeners.

    setContentView() n’est fait que pour être appelée qu’une fois. Pour avoir plusieurs layout tu peux utiliser ViewFlipper mais c’est assez compliqué. Si je dois écrire un tuto là dessus, ce ne serait pas avant des mois.

    L’approche la plus raisonable c’est d’estimer que si tu as plusieurs layout, alors tu as plusieurs Activity. Par example l’application Contact de Google a quatre onglets, mais en fait ce sont 4 activités différentes qui peuvent être utilisées indépendament. C’est une structure souple et extensible.

    Pour lancer une autre activité depuis l’activité courrante, tu peux utiliser un code du genre :

     Intent i = new Intent(this, MyOtherActivity.class);
     i.putExtra("some_param_to_pass",
                        param);
     this.startActivityForResult(i, 
                        Intent.FLAG_ACTIVITY_NEW_TASK );

    Dans deux ou trois tutos, je ferai une explication détaillée.

  11. Profete162 Dit:

    Merci ( encore et toujours)

    Pour le probleme 1) il suffit que tu crées par exemple page2.xml à côté de main et que tu coupes/colles le code du bouton:

    Ca fonctionne sans soucis chez toi?

  12. kevin Dit:

    A priori oui. Tu coupes le code de l’ancien xml vers le nouveau ? Si c’est le cas, assure toi d’avoir un XML bien formé comme expliqué sur http://www.e-vidence.net/?p=174, qui doit contenir notamment :

    - un en-tête XML valide (première ligne = < ?xml version="1.0" encoding="utf-8"?>);
    - un noeud à la racine (une seul balise ouvrante et fermante englobe tout) ;
    - la déclaration du namespace sur le premier noeud (xmlns:android=”http://schemas.android.com/apk/res/android”) et aucun autre.

  13. Profete162 Dit:

    Evidemment.. Mes 2 pages xml fonctionnent tres bien et sont bien formées. Je voyage d’une page à l’autre sans soucis en ayant fait un petit menu.

    Je le répète, je ne fais que déplacer un bouton qui s’appelle “android:id=”@+id/my_quit_button”
    ” d’une page qui fonctionne vers une autre page qui fonctionne par couper coller et mes 2 xml sont bien formés!!!!

    Apparemment ce probleme n’a lieu que chez moi. Je vais refaire l’install d’Eclipse et du sdk

  14. kevin Dit:

    Dans le dossier du SDK, tu as un dossier “tools” qui contient la commande adb.

    Lance “./adb logcat” dans un terminal depuis ce dossier.

    Ensuite lance ton programme.

    Quand ça crashera, tu veras l’intégralité des erreurs, et notamment tout le stack trace Java qui te donneras une bonne idée du problème et là où il se trouve.

    Si tu ne trouve toujours pas, tu peux mettre un lien ici vers un pastebin avec le stack trace.

    Néanmoins, ce genre de problème arrive parfois quand tu fais un findViewById() sur une vue qui n’est pas dans la vue courrante. Si tu déplace ton bouton dans un autre XML et que tu fais findViewById() sur ce bouton alors que tu n’a pas ce fichier chargé, ça fait un NullPointerException.

  15. Profete162 Dit:

    Je pense que tes 4 dernieres lignes expliquent le soucis que je rencontre. Tu as tapé dans le mille.

    Je pense que vais faire plusieurs Activity comme conseille partout pour toutes mes pages et tout seras résolu.

    Encore chapeau bas pour toutes tes connaissances et ton esprit de partager cela.

    Tu peux te dire que c’est grâce à toi que je n’abandonne pas la programmation et que je fais de grandes découvertes tous les jours.

  16. kevin Dit:

    Lol, j’ai dis la même chose au mec de http://www.siteduzero.com il y a des années. Bon, tu continueras la chaîne hein ?

  17. nouvelesprit Dit:

    superbe!!

  18. elwanis Dit:

    merci

  19. olivvv Dit:

    Super tutoriaux.

    Petite question sur cette ligne :
    String hello = getResources().getString(R.string.hello, my_name);

    Je trouve la syntaxe un peu bizarre ( getResources().) .. mais bon, je ne viens pas du monde java.

    Par contre, je ne comprends pas le rôle de ce getResources().
    J’ai testé sans (juste avec le getstring) , cela passe sans problème.

    Une petite explication?

    merci :)
    (Je vois que cela fait un moment que tu n’as pas fait de tutos sur android : c’est finis? ou alors tu as d’autres tutos en cours?)

  20. kevin Dit:

    Hello,

    getRessources() donne accès aux références de toutes les ressources extérieures telles que les chaînes de caractères ou les images. Dans certaines parties du code, on a accès directement à ces ressources depuis this car il représente l’activité en cours. Parfois, ce n’est pas le cas et on a besoin de getRessources(). Par habitude, je le met partout, mais tu as raisons, il n’est pas toujours nécessaire.

    Dans un premier temps, une mise à jour des tutos est prévue pour tenir compte des derniers SDK, ensuite je continuerai sur les bases de données. L’avantage de ne pas monaitiser un blog c’est que je ne suis pas tenu à une quelconque discipline d’écriture, donc ils arriverons quand j’aurais le temps / l’envie / la motivation :-)

Ça se comprend tout seul