24
2010
[Tutoriel Android]Partie 9 – Les threads et boites de progression
Dans une application, nous avons souvent à faire à des processus plus ou moins longs, qui demandent à l’utilisateur de patienter durant le chargement des informations. Si nous effectuons le traitement d’une information à durée déterminée ou indéterminée sur notre application selon le temps que cela prendra, l’interface utilisateur sera bloquée ; ce qui est plutôt gênant et fait penser à celui-ci que l’application a subit un plantage interne. Pour éviter cela, nous pouvons mettre en œuvre les Thread qui permettent d’effectuer une tâche parallèle sans bloquer l’utilisateur.
Définition d’un thread (voir le lien Wikipedia) :
http://fr.wikipedia.org/wiki/Thread_(informatique)
Grâce à un thread, nous pouvons exécuter une fonction sans bloquer notre utilisateur. Si cette exécution est nécessaire pour travailler, nous pouvons bloquer l’utilisateur et l’informer que le chargement des données est en cours et qu’il faut patienter, c’est là que la boite de dialogue est nécessaire. Celle-ci peut avoir un chargement indéterminé, ou déterminé avec le pourcentage d’avancement de notre tâche.
Nous allons commencer par créer notre projet sous Android 1.6 ou supérieur.
Utilisation d’un thread
Dans un projet, il y a plusieurs façons d’implémenter un Thread : la première consiste à utiliser un Thread avec un Runnable intégré et la seconde en implémentant directement le Runnable à notre classe.
Dans le cas d’utilisation de plusieurs Thread, l’implémentation d’un Runnable dans notre Thread est plus facile pour la compréhension ; dans le cas d’un seul Thread rajouté, l’interface Runnable à notre classe ne change que peu de chose, c’est au bon vouloir de chaque développeur.
Nous allons commencer par modifier notre layout de base “Main.xml” pour lui ajouter un bouton sur lequel nous cliquerons pour lancer notre tâche, puis on ajoute le listener pour l’évenement du click sur celui-ci dans notre code.
public class MonActivite extends Activity {
private Button monBouton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
monBouton = (Button) findViewById(R.id.MonBouton);
monBouton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
}
Continuons en rajoutant un nouvelle méthode à notre classe pour traiter des données, nous l’appellerons traitementDesDonnees;
@Override
public void onClick(View v) {
traitementDesDonnees();
}
et pour la méthode :
private void traitementDesDonnees() {
}
Nous allons modifier cette méthode pour implémenter un faux processus de chargement des données.
private void traitementDesDonnees() {
// Boucle de 1 a 10
for (int i = 0; i < 10; i++) {
try {
// Attends 500 millisecondes
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Dans ce traitement, nous faisons une boucle de 1 à 10 et nous attendons 500 millisecondes entre chacune d’entre elle, exécutez cette application.
Lorsque l’on clique sur le bouton, le traitement s’effectue mais bloque l’interface de l’utilisateur et on ne peut rien faire, on a l’impression que le programme est planté.
Nous allons donc utiliser un thread pour effectuer cette tâche, pour travailler en parallèle sans bloquer notre utilisateur. Pour cela, il suffit d’instancier un nouveau thread et de l’exécuter.
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
Voilà notre Thread qui implémente une interface Runnable et sa méthode surchargée run, puis on l’exécute avec un start().
Rajoutons dans notre run notre boucle de tout à l’heure.
private void traitementDesDonnees() {
new Thread(new Runnable() {
@Override
public void run() {
// Boucle de 1 a 10
for (int i = 0; i < 10; i++) {
try {
// Attends 500 millisecondes
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
Lancez l’application et voyez par vous même que l’interface utilisateur n’est plus bloquée.
Bon c’est bien, mais quand on reclique en boucle sur le bouton ça fait quoi ? et bien ça renvoie un traitement de données.
Nous allons avertir l’utilisateur qu’une tâche est donc en cours de traitement, grâce à la classe ProgressDialog.
On déclare notre ProgressDialog
private ProgressDialog progressDialog;
Dans notre méthode onCreate()
progressDialog = new ProgressDialog(this);
Puis dans notre méthode traitementDesDonnees()
private void traitementDesDonnees() {
// On ajoute un message à notre progress dialog
progressDialog.setMessage("Chargement en cours");
// On affiche notre message
progressDialog.show();
new Thread(new Runnable() {
@Override
public void run() {
// Boucle de 1 a 10
for (int i = 0; i < 10; i++) {
try {
// Attends 500 millisecondes
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// A la fin du traitement, on fait disparaitre notre message
progressDialog.dismiss();
}
}).start();
}
Et voilà, lancez notre petit projet :
Bon tout ça c’est bien mais il y a un hic : dans un thread, on ne peut pas modifier notre UI, vous pouvez toujours tenter de modifier le texte du bouton et vous vous retrouverez avec un Force Close et cette exception dans notre fenêtre DDMS :
ERROR/AndroidRuntime(993): Uncaught handler: thread Thread-9 exiting due to uncaught exception
ERROR/AndroidRuntime(993): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Comme le dit le message, on ne pas attaquer notre interface utilisateur lorsque l’on se retrouve dans un Thread.
Ne vous en faites pas, une méthode permet de changer ça facilement, une classe Handler existe, elle permet de prendre la main lorsqu’on lui demande pour afficher une donnée ou autre.
Rajoutons dans notre classe les données suivantes pour notre handler :
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if(msg.what == 0) {
monBouton.setText("C'est bon");
}
};
};
On déclare notre Handler, puis on ajoute la méthode handleMessage, celle-ci nous donne un message en retour dans lequel le what est notre valeur que nous lui avons envoyée, si celle-ci est égale à 0 alors nous modifions notre bouton.
On modifie notre méthode traitementDesDonnees()
private void traitementDesDonnees() {
// On ajoute un message à notre progress dialog
progressDialog.setMessage("Chargement en cours");
// On affiche notre message
progressDialog.show();
new Thread(new Runnable() {
@Override
public void run() {
// Boucle de 1 a 10
for (int i = 0; i < 10; i++) {
try {
// Attends 500 millisecondes
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.sendEmptyMessage(0);
// A la fin du traitement, on fait disparaitre notre message
progressDialog.dismiss();
}
}).start();
}
Notez le handler.sendEmptyMessage(0); qui sera charger d’envoyer à notre handler la valeur 0 pour être traiter.
Lancez notre application.
Et voilà notre bouton est bel et bien modifié.
Barre de progression
Dans notre projet, nous allons ajouter une barre de progression, cela peut être utile si nous connaissons la taille de l’information à charger.
Pour cela, nous allons rajouter une nouvelle méthode nommée traitementDesDonneesAvecPourcentage.
Nous allons reprendre le code de notre autre méthode traitementDesDonnees, mais nous allons modifier notre progressDialog comme ceci :
// On ajoute un message à notre progress dialog
progressDialog.setMessage("Chargement en cours");
// On donne un titre à notre progress dialog
progressDialog.setTitle("Mon chargement");
// On spécifie le style
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// On spécifie le maximum
progressDialog.setMax(10);
// On affiche notre message
progressDialog.show();
Et après notre sleep, nous allons changer la valeur de la progression
// On change la valeur de la progression progressDialog.setProgress(i+1);
Lancez l’application et voyez par vous même :
Notre barre avance au fur et à mesure.
Nous en avons terminé pour aujourd’hui, bon codage à tous.
Les sources du projet : Sources
Articles relatifs
-
http://sitch.fr/ Igor
-
http://sitch.fr/ Igor
-
http://sitch.fr/ Igor
-
http://sitch.fr/ Igor
-
http://SiteWeb Raph
-
http://constantimages.fr Tomsc
-
Vivien-57
Survie
Catégories
- Andengine (5)
- Android (20)
- Application (1)
- Articles (1)
- Non classé (2)
- Programmation (30)
Nuage
Commentaires récents
- Paumé dans [Tutoriel Honeycomb] Partie 1 – Les actions bars
- Acesyde dans [Tutoriel android] Partie 3 – Une petite intention ?
- paul dans [Tutoriel Honeycomb] Partie 1 – Les actions bars
- Sne dans [Tutoriel android] Partie 3 – Une petite intention ?
- Vivien-57 dans [Tutoriel Android] Partie 13 – L’appareil photo
Archives
- janvier 2012 (2)
- novembre 2011 (1)
- octobre 2011 (3)
- juillet 2011 (3)
- juin 2011 (1)
- décembre 2010 (4)
- octobre 2010 (3)
- septembre 2010 (5)
- juillet 2010 (8)
- avril 2010 (6)

Un article de








