web-dev-qa-db-fra.com

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

J'ai une application Android exécutant un fil de discussion. Je veux un message Toast à afficher avec un message.

Lorsque je fais cela, j'obtiens l'exception ci-dessous:

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 pour pousser les messages Toast des threads vers l'interface utilisateur?

89
Amar

J'ai eu cette exception parce que j'essayais de créer une fenêtre contextuelle Toast à partir d'un thread d'arrière-plan.
Toast a besoin d’une activité à pousser vers l’interface utilisateur et les threads ne l’ont pas.
Une solution consiste donc à donner au fil un lien vers l'activité parent et Toast.

Placez ce code dans le fil où vous souhaitez envoyer un message Toast:

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

Conservez un lien vers l'activité parente dans le fil d'arrière-plan 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é parent en tant que paramètre via le constructeur, comme suit:

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

Maintenant, le fil d’arrière-plan peut envoyer des messages Toast à l’écran.

118
Eric Leschinski

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

N'accédez pas à la boîte à outils Android de l'interface utilisateur en dehors du thread d'interface utilisateur pour résoudre ce problème. Android offre plusieurs façons d'accéder au thread d'interface utilisateur à partir d'autres threads. Voici une liste de méthodes pouvant vous aider:

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

Il existe maintenant diverses méthodes pour résoudre ce problème. Je vais l'expliquer par 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();

BOUCLE

Classe utilisée pour exécuter une boucle de message pour un thread. Les threads par défaut ne sont pas associés à une boucle de message; pour en créer un, 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, puis publie les résultats sur le thread d'interface utilisateur, sans vous obliger à gérer vous-même les threads et/ou les 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
    }
}

Gestionnaire

Un gestionnaire vous permet d’envoyer et de traiter les objets Message et Runnable associés au MessageQueue 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;
        }
    });
33
kumar kundan

Voici 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 à la méthode d'être appelée à partir de l'un ou l'autre thread.

Où messageHandler est déclaré dans l'activité en tant que ..

Handler messageHandler = new Handler();
9
Evan Langlois

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

De plus, le toolkit Android UI n'est pas thread-safe. Ainsi, vous ne devez pas manipuler votre interface utilisateur à partir d'un thread de travail - vous devez effectuer toutes les manipulations sur votre interface utilisateur à partir du thread d'interface utilisateur. Ainsi, il existe simplement deux règles pour le modèle à thread unique d'Android:

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

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

S'il vous plaît poster un code, si vous voulez une réponse plus détaillée.

Après la publication du code:

Dans strings.xml

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

Dans 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.

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

ça marche pour moi

2
umar farooq

Vous pouvez simplement utiliser BeginInvokeOnMainThread (). Il appelle une action sur le thread principal du périphérique (UI).

Device.BeginInvokeOnMainThread(() => { displayToast("text to display"); });

C'est simple et fonctionne parfaitement pour moi!

EDIT: Fonctionne si vous utilisez C # Xamarin

1
Vozek