AsyncTask
AsyncTask est une classe permettant le lancement de thread asynchrone en tâche de fond tout en ayant la possibilité d'informer simplement l'UI Thread de l'état d'avancement.
Ces threads doivent donc avoir une fin et ne doivent pas tourner en boucle infinie !
Les avantages:
- Pas besoin de créer ou de terminer le thread en arrière plan.
- Communication Thread en arrière plan/ UI Thread simplifiée.
Les méthodes
Comme il s'agit de nous simplifier la vie, AsyncTask met à disposition 4 méthodes dont une obligatoire:
doInBackground(): Il s'agit du traitement qui sera lancé en arrière plan (donc dans un thread). Elle est donc évidemment obligatoire, sinon AsyncTask ne serait pas utile !
Signature: doInBackground(Params...)
onProgressUpdate(): Méthode lancée dans l'UI Thread. Elle permettra d'indiquer l'avancement du traitement en tâche de fond à l'utilisateur. Cette méthode sera déclenchée uniquement en utilisant publishProgress() depuis le code de la méthode doInBackground().
Signature: onProgressUpdate(Progress...)
onPreExecute(): Cette méthode est déclenchée depuis l'UI Thread avant le lancement du thread en arrière plan. Elle pourra par exemple permettre l'initialisation d'une progress bar ou avertir l'utilisateur du lancement du traitement en arrière plan.
Signature: onPreExecute()
onPostExecute(): Pour informer de la fin d'un traitement en arrière plan ou pour cacher la progress bar par exemple.
Signature: onPostExecute(Result)
onPostExecute()
n'est pas systématiquement déclenchée ! Il est en effet
possible d'interrompre une tâche en arrière plan. Il n'y aura pas
d'appel onPostExecute() mais à onCancelled(Object).
Points importants sur les méthodes de AsyncTask
Les trois méthodes
onProgressUpdate(), onPreExecute() et onPostExecute() s'exécutant sous
l'UI thread, elles ne doivent pas effectuer de traitement lourd sous peine d'ANR
!
Ne jamais lancer
la méthode onProgressUpdate directement, toujours passer par publishProgress()
! Même remarque pour les autres méthodes !
Création de votre classe de tâches asynchrones
Votre classe devra étendre la classe AsyncTask de la manière suivante
private class MyTask extends AsyncTask<Params, Progress, Result> { ...
}
Les types de paramètres des méthodes
Comme vous pouvez le constater, les signatures des méthodes sont plutôt particulières.
Les types de la classes AsyncTask sont en effet génériques. Vous pouvez donc utiliser ce que vous voulez, il suffit de le préciser lors de la déclaration de votre classe.
Les trois types utilisés par AsyncTask sont les suivants:
Params: Type de paramètres qui seront passés à doInBackground()
Progress: Type de paramètres qui seront passés à onProgressUpdate().
Result: Type de paramètres qui seront passés à onPostExecute().
Si vous ne voulez passer aucun paramètre, vous pourrez faire
private class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected void onPreExecute() {
...
}@Override
protected void onProgressUpdate(Void... rien){
...}
@Override
protected Void doInBackground(Void... rien) {...
}
@Override
protected void onPostExecute(Void rien) {...
}
}
Si vous voulez passer une liste d'url à récupérer et le % d'avancement:
private class MyTask extends AsyncTask<URL, Integer, Void> {
@Override
protected void onPreExecute() {
...
}@Override
protected void onProgressUpdate(Interger... pourcentage){// Afficher le pourcentage
...
}
@Override
protected Void doInBackground(URL... urls) {int count = urls.length; // Récupérer le nombre d'urls passées
...
}
@Override
protected void onPostExecute(Void rien) {...
}
}
etc...
Où créer, instancier votre classe AsyncTask
Votre classe devra être chargée, instanciée et exécutée depuis un UI Thread !
Exécuter votre tâche en arrière plan
Pour exécuter notre tâche en arrière plan, la méthode
execute(Params... params) sera utilisée.
Il sera possible
de lancer plusieurs tâches...
Interrompre l'exécution d'une tâche
Il est possible de mettre fin à votre tâche en arrière plan (par exemple, pour traiter la rotation de l'écran qui va détruire l'UI Thread, volontairement (abandon de l'utilisateur), suite à une demande du système d'arrêter votre UI Thread en arrière plan par manque de mémoire).
Dans ce cas, il faut utiliser la méthode cancel(boolean mayInterruptIfRunning).
mayInterruptIfRunning à vrai indique qu'il faut détruire le thread s'il est déjà en cours d'exécution, si le thread n'est pas en cours d'exécution, il ne s'exécutera jamais. A faux, cela signifie que le thread ne pourra jamais démarrer, mais il ne s'arrête pas si déjà en cours d'exécution.
On utilisera false
si le thread n'est pas conçu pour pouvoir s'interrompre.
Suite à l'invocation de cette méthode, doInBackGround() va s'interrompre (en retournant éventuellement un résultat) mais onPostExecute() ne sera pas exécutée et sera remplacée par un appel à onCancelled().
Il peut être
intéressant de contrôler la valeur en retour de isCancelled() périodiquement
depuis doInBackGround() afin de sortir le plus rapidement possible de cette
méthode (et tout spécialement dans les boucles du traitement !).
La méthode protected void onCancelled (Result result) est déclenchée lorsque l'UI thread lance un cancel(boolean) et que doInBackground(Object[]) est terminée. result étant la valeur retournée éventuellement par doInBackGround(). Si vous n'utilisez pas cette méthode, alors onCancelled() sera lancée automatiquement (vous n'avez pas à y faire appel !).
Il est préférable
de surcharger onCancelled (Result result) que onCancelled (), mais tout dépendra
de la version de l'API utilisée (à partir de la 11 pour onCancelled
(Result result)).
Etat de la tâche en arrière plan
La méthode getStatus() retourne l'état de la tâche:
AsyncTask.Status.FINISHED: onPostExecute(Result) a terminé son travail.
AsyncTask.Status.PENDING: indique que le traitement n'a pas encore été
démarré
AsyncTask.Status.RUNNING: Le traitement est en cours.
Exemple de code
Le source AsyncTaskActivity.java
Ce programme met en oeuvre pas mal de choses:
- Une progress bar afin de voir évoluer notre traitement.
- Un Toggle button ON/OFF pour lancer/interrompre notre tâche de fond (avec un listener sur le bouton).
- Les toasts pour afficher l'avancé globale du traitement.
Puis le fichier layout main.xml
Le fichier Strings.xml
Et le fichier AndroidManifest.xml