95 votes

java.lang.RuntimeException : Impossible de créer un gestionnaire dans un thread qui n'a pas appelé Looper.prepare() ;

J'ai une application Android qui exécute un fil de discussion. Je veux qu'un message Toast s'affiche avec un message.

Lorsque je fais cela, j'obtiens l'exception suivante :

Logcat trace :

FATAL EXCEPTION: Timer-0 
 java.lang.RuntimeException: Can't create handler inside thread that has not 
    called Looper.prepare()

 at android.os.Handler.<init>(Handler.java:121)
 at android.widget.Toast$TN.<init>(Toast.java:322)
 at android.widget.Toast.<init>(Toast.java:91)
 at android.widget.Toast.makeText(Toast.java:238) 

Existe-t-il une solution de contournement pour pousser les messages Toast des threads vers l'interface utilisateur ?

125voto

Eric Leschinski Points 14289

J'ai obtenu cette exception parce que j'essayais de faire apparaître un Toast à partir d'un fil de fond.
Toast a besoin d'une activité à pousser vers l'interface utilisateur et les fils n'en ont pas.
Une solution consiste donc à donner au fil de discussion un lien vers l'activité parente et de porter un toast à celle-ci.

Mettez ce code dans le fil de discussion où vous voulez envoyer un message Toast :

parent.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(parent.getBaseContext(), "Hello", Toast.LENGTH_LONG).show();
    }
});

Gardez un lien vers l'activité mère dans le fil de fond qui a créé ce fil. Utilisez la variable parent dans votre classe de fil :

private static YourActivity parent;

Lorsque vous créez le fil, passez l'activité parente comme paramètre dans le constructeur comme ceci :

public YourBackgroundThread(YourActivity parent) {
    this.parent = parent;
}

Maintenant, le fil de fond peut pousser les messages Toast à l'écran.

33voto

kumar kundan Points 1353

Android fonctionne essentiellement sur deux types de threads, à savoir le thread de l'interface utilisateur et le thread d'arrière-plan. Selon la documentation d'Android -

N'accédez pas à la boîte à outils de l'interface utilisateur d'Android en dehors du thread de l'interface utilisateur. Pour résoudre ce problème, Android propose plusieurs moyens d'accéder au thread de l'interface utilisateur à partir d'autres threads. Voici une liste de méthodes qui peuvent vous aider :

Activity.runOnUiThread(Runnable)  
View.post(Runnable)  
View.postDelayed(Runnable, long)

Il existe aujourd'hui différentes méthodes pour résoudre ce problème. Je vais l'expliquer par un exemple de code

runOnUiThread

new Thread()
{
    public void run()
    {
        myactivity.this.runOnUiThread(new runnable()
        {
            public void run()
            {
                //Do your UI operations like dialog opening or Toast here
            }
        });
    }
}.start();

LOOPER

Classe utilisée pour exécuter une boucle de messages pour un thread. Par défaut, les threads ne sont pas associés à une boucle de messages ; pour en créer une, appelez prepare() dans le thread qui doit exécuter la boucle, puis loop() pour qu'il traite les messages jusqu'à ce que la boucle soit arrêtée.

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }

AsyncTask

AsyncTask vous permet d'effectuer un travail asynchrone sur votre interface utilisateur. Il effectue les opérations de blocage dans un thread de travail et publie ensuite les résultats sur le thread de l'interface utilisateur, sans que vous ayez à gérer vous-même des threads et/ou des gestionnaires.

public void onClick(View v) {
    new CustomTask().execute((Void[])null);
}

private class CustomTask extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... param) {
        //Do some work
        return null;
    }

    protected void onPostExecute(Void param) {
        //Print Toast or open dialog
    }
}

Manipulateur

Un Handler permet d'envoyer et de traiter les objets Message et Runnable associés à la MessageQueueue d'un thread.

Message msg = new Message();

    new Thread()
    {
        public void run()
        {
            msg.arg1=1;
            handler.sendMessage(msg);
        }
    }.start();

    Handler handler = new Handler(new Handler.Callback() {

        @Override
        public boolean handleMessage(Message msg) {
            if(msg.arg1==1)
            {
                //Print Toast or open dialog        
            }
            return false;
        }
    });

10voto

Evan Langlois Points 3017

Voilà ce que j'ai fait :

  public void displayError(final String errorText) {
    Runnable doDisplayError = new Runnable() {
        public void run() {
            Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show();
        }
    };
    messageHandler.post(doDisplayError);
}

Cela devrait permettre d'appeler la méthode à partir de n'importe quel thread.

Où le messageHandler est déclaré dans l'activité comme

Handler messageHandler = new Handler();

6voto

baptisterobert Points 126

En http://developer.Android.com/guide/components/processes-and-threads.html :

En outre, la boîte à outils de l'interface utilisateur d'Android n'est pas à l'épreuve des fils. Ainsi, vous ne devez pas manipuler votre interface utilisateur depuis un fil de travail -vous devez faire tout manipulation de votre interface utilisateur à partir du thread UI. Ainsi, il y a il y a simplement deux règles pour le modèle de thread unique d'Android :

  1. Ne pas bloquer le thread de l'interface utilisateur
  2. N'accédez pas à la boîte à outils de l'interface utilisateur Android en dehors du fil d'exécution de l'interface utilisateur.

Vous devez détecter l'inactivité d'un thread de travail et afficher un toast dans le thread principal.

Si vous souhaitez obtenir une réponse plus détaillée, veuillez envoyer du code.

Après la publication du code :

En strings.xml

<string name="idleness_toast">"You are getting late do it fast"</string>

En YourWorkerThread.java

Toast.makeText(getApplicationContext(), getString(R.string.idleness_toast), 
    Toast.LENGTH_LONG).show();

N'utilisez pas AlertDialog, faites un choix. AlertDialog et Toast sont deux choses différentes.

4voto

umar farooq Points 331
runOnUiThread(new Runnable(){
   public void run() {
     Toast.makeText(getApplicationContext(), "Status = " + message.getBody() , Toast.LENGTH_LONG).show();
   }
 });

cela fonctionne pour moi

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X