Tâches Asynchrones (AsyncTask) et Android

Aujourd’hui, nous allons aborder un sujet important dans le monde Android : les tâches asynchrones (que nous appellerons AsyncTask dans la suite de cet article).

Introduction aux AsyncTask

Les AsyncTask permettent de réaliser des opérations de manière asynchrones comme la classe Thread.

On peut remarquer que les AsyncTask sont faciles à utiliser et à implémenter ce qui en fait un composant essentiel. Lorsque l’on appelle une AsyncTask, un Thread secondaire est créé automatiquement et la communication entre les différents Threads est simplifiée.

Pourquoi utiliser une AsyncTask?

Dans une application Android, les opérations consommatrices de ressources (requête HTTP, calculs, etc…) doivent s’effectuer dans des Threads séparés.

Imaginons que l’on ait un calcul très consommateur de ressources. S’il s’exécute dans l’UI Thread, alors ce dernier reste « bloqué » le temps que le calcul se termine. S’il reste bloqué trop longtemps, le système affiche un message d’erreur et ferme l’application.

Ainsi, en utilisant une AsyncTask, on effectue l’ensemble des opérations consommatrices de ressources dans un Thread séparé et on fait évoluer l’UI Thread en fonction de l’avancement de ces tâches.

Comment utiliser une AsyncTask?

Voyons maintenant un exemple d’implémentation où nous utiliserons une ProgressBar pour symboliser l’avancement de la tâche asynchrone. Nous lancerons alors la tâche asynchrone à l’appui sur un bouton.

Voici alors le layout que nous utiliserons :

<!--?xml version="1.0" encoding="utf-8"?-->

    <button>

Une fois ce layout créé, intéressons nous maintenant à l’activity de notre tutoriel. Il s’agira de définir le lancement d’une tâche asynchrone au cours du click sur le bouton. Nous définirons alors une classe interne qui représentera la tâche asynchrone à exécuter :

package com.yoannzimero.tutorial;

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 TestAsyncTaskActivity extends Activity {

	private ProgressBar progressBar;
    private Button button;

    /**
     * Tâche asynchrone à exécuter lors de l'appui sur le bouton
     * Le premier paramètre de généricité (Void) représente le type de paramètre à passer dans la méthode doInBackground
     * Le second paramètre de généricité (Integer) représente le type de paramètre à passer à la méthode onProgressUpdate
     * Le troisième paramètre de généricité (Void) représente le type de paramètre à passer à la méthode onPostExecute
     */
    private class TacheAsynchrone extends AsyncTask {

    	// Méthode exécutée au début de l'execution de la tâche asynchrone
        @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
            progressBar.setProgress(values[0]);
        }

        @Override
        protected Void doInBackground(Void... arg0) {
            int progress;
            for (progress = 0; progress                 for (int i = 0; i < 1000000; i++){
                	// Ne fait rien mais fait juste passer du temps
                }

                // publishProgress met à jour l'interface en invoquant la méthode onProgressUpdate
                publishProgress(progress);
                progress++;
            }
            return null;
        }

        // Méthode exécutée à la fin de l'execution de la tâche asynchrone
        @Override
        protected void onPostExecute(Void result) {
            Toast.makeText(getApplicationContext(), "Le traitement asynchrone est terminé", Toast.LENGTH_LONG).show();
        }
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // On récupère les composants de notre layout
        progressBar = (ProgressBar) findViewById(R.id.progressbarAsync);
        button = (Button) findViewById(R.id.buttonLaunch);

        // On met un Listener sur le bouton
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
            	// On lance la tâche asynchrone
            	TacheAsynchrone tacheAsynchrone = new TacheAsynchrone();
            	tacheAsynchrone.execute();
            }
        });
    }
}

Vous remarquerez la présence de trois paramètres de généricités qui définissent l’AsyncTask :

  • Le premier permet de définir le type de paramètre passé à la méthode doInBackground
  • Le second permet de définir le type de paramètre passé à la méthode onProgressUpdate
  • Le troisième permet de définir le type de paramètre passé à la méthode onPostExecute

Une AsyncTask doit impérativement 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 doit pas appeler la méthode onProgressUpdate directement.

Attention, les 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.

Vous trouverez les sources de ce tutoriel ici