Les AsyncTask

 

Une AsyncTask permet de réaliser des tâches de manière asynchrone (en arrière plan). L’avantage de l’AsyncTask est sa simplicité d’utilisation et d’implémentation.
Le Thread (processus) secondaire est créé automatiquement et la communication entre les différents Thread est simplifiée.

Lors du développement d’une application, à fortiori sous Android car les appareils fonctionnant sous cet environnement sont souvent "légers", toutes les tâches consommatrices de ressources (requêtes http (donc consommation de webservice), calculs lourds, …) doivent se faire dans un Thread séparé. Sinon, le système affiche un message d’erreur et ferme l’application lorsque le Thread principal (appelé UI Thread) est bloqué trop longtemps.

image

Mise en place du projet

Illustration à partir d'un projet Android appelé AsyncBigCalcul qui effectue un traitement long de manière asynchrone. En fait, une énorme boucle.
Premièrement, modification du layout main.xml en modifiant le contenu du TextView initial  ("Progression de la tâche asynchrone" au lieu de "Hello World") et  en ajoutant un Button et une ProgressBar. Le premier servira à lancer le traitement ; la seconde à afficher la progression du traitement.  Voici le code XML généré, après modification :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
 
    <Button
        android:layout_marginTop="10dp"
        android:id="@+id/btnLaunch"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Lancer la tâche" />
    
    <TextView        
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Progression de la tâche asynchrone:" />
 
    <ProgressBar
        android:id="@+id/pBAsync"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_margin="10dp"
        android:layout_height="wrap_content" />    
</LinearLayout>

L’activité principale

Comme habituellement, on récupère les composants définis dans le layout puis on ajoute un écouteur (listener) sur le bouton afin qu’à chaque clic on exécute une nouvelle instance de BigCalcul qui est la classe asynchrone (exécutée en tâche de fond donc).
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
 
public class AsyncBigCalculActivity extends Activity
{
 
        private ProgressBar mProgressBar;
        private Button mButton;
 
        /** Appelé quand l'activité est créée */
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
               super.onCreate(savedInstanceState);
               setContentView(R.layout.main);
 
               // On récupère les composants du layout
               mProgressBar = (ProgressBar) findViewById(R.id.pBAsync);
               mButton = (Button) findViewById(R.id.btnLaunch);
 
               // On met un écouteur sur le bouton
               mButton.setOnClickListener(new OnClickListener()
               {
                       @Override
                       public void onClick(View arg0)
                       {
                               BigCalcul calcul=new BigCalcul();
                               calcul.execute();
                       }
               });
        }
}

La classe BigCalcul (classe asynchrone)

La classe asynchrone BigCalcul hérite impérativement d’AsyncTask. Elle est ici en classe privée mais elle aurait pu être écrite à part. Seule la méthode doInBackGround doit être obligatoirement redéfinie :

private class BigCalcul extends AsyncTask<Void, Integer, Void>
{
        @Override
        protected void onPreExecute()
        {
               super.onPreExecute();
               Toast.makeText(getApplicationContext(), "Début du traitement asynchrone", Toast.LENGTH_LONG).show();
        }
 
        @Override
        protected void onProgressUpdate(Integer... values)
        {
               super.onProgressUpdate(values);
               // Mise à jour de la ProgressBar
               mProgressBar.setProgress(values[0]);
        }
 
        @Override
        protected Void doInBackground(Void... arg0)
        {
               int progress;
               for (progress=0;progress<=100;progress++)
               {
                       for (int i=0; i<1000000; i++){}
                       //la méthode publishProgress met à jour l'interface en invoquant la méthode onProgressUpdate
                       publishProgress(progress);
                       progress++;                           
               }       
               return null;
        }
 
        @Override
        protected void onPostExecute(Void result) {
               Toast.makeText(getApplicationContext(), "Le traitement asynchrone est terminé", Toast.LENGTH_LONG).show();
        }
}

Explications :
Les trois paramètres attendus lors de la déclaration sont des types génériques :

·   Le 1er est le type des paramètres fournis à la tâche (ici aucun paramètre transmis è Void)

·   Le 2nd est le type de données transmises durant la progression du traitement (ici int)

·   Enfin le troisième est le type du résultat de la tâche (ici aucun résultat transmis è Void)

Une AsyncTask doit obligatoirement implémenter la méthode doInBackground. C’est elle qui réalisera le traitement de manière asynchrone dans un Thread séparé. Les méthodes onPreExecute (appelée avant le traitement), onProgressUpdate (appelée lorsque vous souhaitez afficher sa progression) et onPostExecute (appelée après le traitement) sont optionnelles. Un appel à la méthode publishProgress permet la mise à jour de la progression. On ne peut pas appeler la méthode onProgressUpdate directement.

NOTE: Attention, ces trois méthodes (onPreExecute, onProgressUpdate et onPostExecute) s’exécutent depuis l’UI Thread ! C’est d’ailleurs grâce à cela qu’elles peuvent modifier l’interface. On ne doit donc pas y effectuer de traitements lourds.

Ce qui donnera :
image

image

image