83 votes

Impossible de créer un handler dans un thread qui n'a pas appelé Looper.prepare()

J'ai une activité, et dans celle-ci j'ai une classe.

text=new Dynamictext(...);
text.setText("txt");

Dans mon DynamicText java, j'ai ce code :

public void setText(String text) {
    this.text=text;
    new asyncCreateText().execute();
    //this.createText(text);
}

//private Handler handler = new Handler();

private class asyncCreateText extends AsyncTask<Void, Void, Void> 
{
    @Override
    protected Void doInBackground(Void... unused) {
        return null;
    }

    @Override
    protected void onPostExecute(Void unused) {

    }
}

J'ai compris :

ERROR/AndroidRuntime(5176) : Causé par : java.lang.RuntimeException : Impossible de créer un gestionnaire dans un thread qui n'a pas appelé Looper.prepare().

Comment puis-je gérer cette erreur ?

ERROR/AndroidRuntime(5370): java.lang.ExceptionInInitializerError
ERROR/AndroidRuntime(5370):     at com.l.start.DynamicText.setText(DynamicText.java:125)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.initfonts(OpenGLRenderer.java:168)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.init(OpenGLRenderer.java:119)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.onSurfaceChanged(OpenGLRenderer.java:90)
ERROR/AndroidRuntime(5370):     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1120)
ERROR/AndroidRuntime(5370):     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:975)

ERROR/AndroidRuntime(5370): Caused by: java.lang.RuntimeException: 
    Can't create handler inside thread that has not called Looper.prepare()
ERROR/AndroidRuntime(5370):     at android.os.Handler.<init>(Handler.java:121)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
ERROR/AndroidRuntime(5370):     ... 6 more

0 votes

Pouvez-vous afficher la trace complète de la pile ? Vous semblez appeler une méthode de l'interface utilisateur à partir du fil d'arrière-plan ou autre.

1 votes

Este expliquera la question en détail.

1 votes

147voto

Reuben Scratton Points 22314

L'erreur est explicite... doInBackground() s'exécute sur un fil d'arrière-plan qui, puisqu'il n'est pas destiné à tourner en boucle, n'est pas connecté à un fil d'arrière-plan. Looper .

Il est fort probable que vous ne souhaitiez pas du tout instancier directement un Handler... quelles que soient les données que votre doInBackground() Les retours de l'implémentation seront transmis à onPostExecute() qui s'exécute sur le fil d'exécution de l'interface utilisateur.

   mActivity = ThisActivity.this; 

    mActivity.runOnUiThread(new Runnable() {
     public void run() {
     new asyncCreateText().execute();
     }
   });

AJOUTÉ À LA SUITE DU STACKTRACE APPARAISSANT EN QUESTION :

On dirait que tu essaies de lancer un AsyncTask d'un fil de rendu GL... ne faites pas ça parce qu'ils ne seront jamais Looper.loop() soit. Les AsyncTasks sont vraiment conçues pour être exécutées uniquement à partir du thread de l'interface utilisateur.

La solution la moins perturbante serait probablement d'appeler Activity.runOnUiThread() avec un Runnable qui donne le coup d'envoi de votre AsyncTask .

1 votes

La réponse est tout à fait correcte. Toutefois, dans mon cas, il m'a suffi de supprimer certains Toasts (qui tentent de s'exécuter sur le thread de l'interface utilisateur) de ma classe personnalisée FtpUpload AsyncTask et voilà.

0 votes

La même erreur m'arrive et je ne sais pas comment la résoudre. J'ai lu la description mais je n'ai pas compris comment le faire.

32voto

Lisandro Points 676

Toutes les réponses ci-dessus sont correctes, mais je pense que cet exemple est le plus simple possible :

public class ExampleActivity extends Activity {
    private Handler handler;
    private ProgressBar progress;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        progress = (ProgressBar) findViewById(R.id.progressBar1);
        handler = new Handler();
    }

    public void clickAButton(View view) {
        // Do something that takes a while
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                handler.post(new Runnable() { // This thread runs in the UI
                    @Override
                    public void run() {
                        progress.setProgress("anything"); // Update the UI
                    }
                });
            }
        };
        new Thread(runnable).start();
    }
}

Il s'agit de mettre à jour une barre de progression dans le thread de l'interface utilisateur à partir d'un thread complètement différent passé par la méthode post() du gestionnaire déclaré dans l'activité.

J'espère que cela vous aidera !

23voto

Ayman Mahgoub Points 505

Vous créez le gestionnaire dans le fil d'arrière-plan de cette façon

private void createHandler() {
        Thread thread = new Thread() {
          public void run() {
               Looper.prepare();

               final Handler handler = new Handler();
               handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                       // Do Work
                        handler.removeCallbacks(this);
                        Looper.myLooper().quit();
                   }
                }, 2000);

                Looper.loop();
            }
        };
        thread.start();
    }

12voto

Eli Points 116

Activity.runOnUiThread() ne fonctionne pas pour moi. J'ai contourné ce problème en créant un fil de discussion ordinaire de cette façon :

public class PullTasksThread extends Thread {
   public void run () {
      Log.d(Prefs.TAG, "Thread run...");
   }
}

et l'appeler depuis la mise à jour GL de cette façon :

new PullTasksThread().start();

0 votes

Cette solution a fonctionné pour moi en l'appelant depuis GL mais vous devez être sûr que vous n'appelez pas Toasts sur la méthode d'exécution ! AsyncTask n'a pas fonctionné en l'appelant depuis GL. Merci !

0 votes

Cela fonctionne très bien pour moi en remplaçant une AsyncTask. Merci !

5voto

user2560131 Points 11

Essayez de vous exécuter en asynchrone depuis le thread de l'interface utilisateur. J'ai rencontré ce problème alors que je ne faisais pas la même chose !

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