Utiliser une ProgressDialog dans ses applications Android

Image non disponible

Le but de ce tutorial est d'expliquer comment utiliser une ProgressDialog dans son application Android. Il peut être parfois utile d'afficher une barre de progression renseignant l'utilisateur sur l'avancement. Android fournit un moyen via la ProgressDialog pour les phases d'attente.
1 commentaire Donner une note à l'article (5)

Article lu   fois.

Les deux auteurs

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Présentation

Qui dit longue opération dit souvent Thread. Or Android est connu pour bien différencier l'affichage du traitement (Modèle MVC) et seul le Thread propriétaire des objets graphiques (View) peut les modifier. En gros, lorsque votre Activity charge le layout, elle est la seule à pouvoir agir dessus. C'est ce que nous verrons dans la partie Fonctionnement.

II. Fonctionnement

1. Cas Simple

Prenons l'exemple d'une application ayant à effectuer 2 opérations assez longues consécutives (doLongOperation1 et doLongOperation2). Elles sont exécutées dans un nouveau Thread, en plus du Thread de l'Activity, qui sera lui, démarré depuis l'Activity.
Au moment où ce second Thread est démarré, on obtient quelque chose du genre :

Image non disponible

Ce qui correspond à un code comme celui-ci:

Exemple
Sélectionnez

private void compute() {
  mProgressDialog = ProgressDialog.show(this, "Please wait",
          "Long operation starts...", true);
 
  new Thread((new Runnable() {
      @Override
      public void run() {
          doLongOperation1();
          doLongOperation2();
      }
  })).start();
  // ...
}
			

2. Afficher un Message

Durant l'exécution des opérations, on peut imaginer que l'on ait besoin d'informer l'utilisateur sur le type d'opération en cours et donc mettre à jour le message de la ProgressDialog. Pour ce faire on pourrait utiliser la méthode setMessage de ProgressDialog.

Ce qui correspond à un code comme celui-ci :

Exemple
Sélectionnez

private void compute() {
  mProgressDialog = ProgressDialog.show(this, "Please wait",
          "Long operation starts...", true);
 	
  new Thread((new Runnable() {
      @Override
      public void run() {
          mProgressDialog.setMessage("Doing long operation 1...");
          doLongOperation1();
          mProgressDialog.setMessage("Doing long operation 2...");
          doLongOperation2();
      }
  })).start();
  // ...
}
				


Mais, comme nous l'avons indiqué précédement, seul le Thread propriétaire des objets graphiques peut les modifier. L'objet mProgressDialog, créé dans le Thread de l'Activity, ne peut être modifier par un Thread annexe, au risque de lancer une CalledFromWrongThreadException avec le message au combien explicite :

Only the original thread that created a view hierarchy can touch its views.

Pour réaliser notre opération, il faut donc que le second Thread soit capable d'informer le Thread de l'Activity. C'est ce que propose la classe Handler avec le principe des objets Message qu'elle véhicule. En gros un Handler, possède une queue (une file) de messages qu'il dépile un à un. Ces messages sont constitués d'un identifiant (int what) et peuvent contenir des données. Il suffit de créer un objet de type Handler, et de l'utiliser pour préparer (appel à obtainMessage), envoyer (appel à sendMessage) et recevoir (override de handleMessage) les objets de type Message

Pour notre exemple, on définira 3 types de messages avec les 3 identifiants suivants :

1. MSG_ERR: une erreur s'est produite, la ProgressDialog disparait et on informe l'utilisateur
2. MSG_IND: une indication en cours de traitement a besoin d'être donnée à l'utilisateur (via la ProgressDialog)
3. MSG_CNF: le traitement est terminé, on confirme à l'utilisateur que tout s'est bien passé (la ProgressDialog disparait).

Bref, dans le cas nominal, on obtient donc ce qui suit:

Image non disponible
Exemple
Sélectionnez

package com.jde.tutorial;
 
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
 
public class ProgressBarActivity extends Activity {
 
protected ProgressDialog mProgressDialog;
private Context mContext;
private ErrorStatus status;
 
public static final int MSG_ERR = 0;
public static final int MSG_CNF = 1;
public static final int MSG_IND = 2;
 
public static final String TAG = "ProgressBarActivity";
 
enum ErrorStatus {
    NO_ERROR, ERROR_1, ERROR_2
};
 
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mContext = this;
 
    // registers the OnClickListener to our button
    ((Button) findViewById(R.id.btn))
            .setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    compute();
                }
            });
}
 
private void compute() {
    mProgressDialog = ProgressDialog.show(this, "Please wait",
            "Long operation starts...", true);
 
    // useful code, variables declarations...
    new Thread((new Runnable() {
        @Override
        public void run() {
            Message msg = null;
            String progressBarData = "Doing long operation 1...";
 
            // populates the message
            msg = mHandler.obtainMessage(MSG_IND, (Object) progressBarData);
 
            // sends the message to our handler
            mHandler.sendMessage(msg);
 
            // starts the first long operation
            status = doLongOperation1();
 
            if (ErrorStatus.NO_ERROR != status) {
                Log.e(TAG, "error while parsing the file status:" + status);
 
                // error management, creates an error message
                msg = mHandler.obtainMessage(MSG_ERR,
                        "error while parsing the file status:" + status);
                // sends the message to our handler
                mHandler.sendMessage(msg);
            } else {
                progressBarData = "Doing long operation 2...";
                mProgressDialog.setMessage(progressBarData);
 
                // populates the message
                msg = mHandler.obtainMessage(MSG_IND,
                        (Object) progressBarData);
 
                // sends the message to our handler
                mHandler.sendMessage(msg);
 
                // starts the second long operation
                status = doLongOperation2();
 
                if (ErrorStatus.NO_ERROR != status) {
                    Log.e(TAG, "error while computing the path status:"
                            + status);
                    // error management,creates an error message
                    msg = mHandler.obtainMessage(MSG_ERR,
                            "error while computing the path status:"
                                    + status);
                    // sends the message to our handler
                    mHandler.sendMessage(msg);
                } else {
                    msg = mHandler.obtainMessage(MSG_CNF,
                            "Parsing and computing ended successfully !");
                    // sends the message to our handler
                    mHandler.sendMessage(msg);
                }
            }
        }
    })).start();
    // ...
}
 
 /** fake operation for testing purpose */
protected ErrorStatus doLongOperation1() {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
    }
    return ErrorStatus.NO_ERROR;
}

/** fake operation for testing purpose */
protected ErrorStatus doLongOperation2() {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
    }
    return ErrorStatus.NO_ERROR;
}
 
final Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
        String text2display = null;
        switch (msg.what) {
        case MSG_IND:
            if (mProgressDialog.isShowing()) {
                mProgressDialog.setMessage(((String) msg.obj));
            }
            break;
        case MSG_ERR:
            text2display = (String) msg.obj;
            Toast.makeText(mContext, "Error: " + text2display,
                    Toast.LENGTH_LONG).show();
            if (mProgressDialog.isShowing()) {
                mProgressDialog.dismiss();
            }
            break;
        case MSG_CNF:
            text2display = (String) msg.obj;
            Toast.makeText(mContext, "Info: " + text2display,
                    Toast.LENGTH_LONG).show();
            if (mProgressDialog.isShowing()) {
                mProgressDialog.dismiss();
            }
            break;
        default: // should never happen
            break;
        }
    }
};
 
}
			

C'est à travers la méthode surchargée handleMessage que le message est dépilé. On teste ensuite le type de message (what) et on applique le traitement désiré.

Note: dans la méthode handleMessage, on se trouve à nouveau dans le Thread de l'Activity, c'est donc pour ça que l'opération est possible.

Voila ce que vous devriez avoir :

Image non disponible
Image non disponible
Image non disponible

III. Remerciements

Je tiens à remercier tout particulièrement Feanorinhttp://www.developpez.net/forums/u35388/feanorin/ qui a mis ce tutoriel au format Developpez.com.
Merci également à JF Jousseaumehttp://www.developpez.net/forums/u195853/sepia/ d'avoir pris le temps de le relire et de le corriger.

IV. Lien

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2011 Axon de Tuto Mobile. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.