web-dev-qa-db-fra.com

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

J'ai une activité et 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) {

    }
}

Je reçois:

ERROR/AndroidRuntime (5176): Causée par: Java.lang.RuntimeException: Impossible de créer un gestionnaire dans un thread n'ayant 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
79
lacas

L'erreur est explicite ... doInBackground() est exécuté sur un thread d'arrière-plan qui, puisqu'il n'est pas destiné à être mis en boucle, n'est pas connecté à un Looper.

Il est fort probable que vous ne souhaitiez pas directement instancier directement un gestionnaire ... les données renvoyées par votre implémentation doInBackground() seront transmises à onPostExecute(), qui s'exécute sur le thread d'interface utilisateur.

   mActivity = ThisActivity.this; 

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

AJOUTE APRES LA QUESTION QUI SUIT: L'empilement apparaît

On dirait que vous essayez de démarrer un AsyncTask à partir d'un thread de rendu GL ... ne faites pas cela parce qu'ils ne le feront jamais Looper.loop() non plus. AsyncTasks sont vraiment conçus pour être exécutés à partir du thread d'interface utilisateur uniquement.

Le correctif le moins perturbant serait probablement d’appeler Activity.runOnUiThread() avec un Runnable qui déclenche votre AsyncTask.

145
Reuben Scratton

Toutes les réponses ci-dessus sont correctes, mais je pense que ceci est l'exemple 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();
    }
}

Cela permet de mettre à jour une barre de progression dans le thread d'interface utilisateur à partir d'un thread complètement différent transmis via la méthode post () du gestionnaire déclaré dans l'activité.

J'espère que ça aide!

31
Lisandro

Vous créez le gestionnaire en arrière-plan de cette manière

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();
    }
20
Ayman Mahgoub

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

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

et en l'appelant depuis le GL update de cette façon:

new PullTasksThread().start();
11
Eli

Essayez de lancer votre asynctask à partir du thread d'interface utilisateur. J'ai fait face à ce problème quand je ne faisais pas la même chose!

4
user2560131

Essaye ça

    Handler mHandler = new Handler(Looper.getMainLooper());
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
 //your code here that talks with the UI level widgets/ try to access the UI 
//elements from this block because this piece of snippet will run in the UI/MainThread.                                     
                            }
                        });
2
Marcos Militão