Es kann kein Handler innerhalb eines Threads erstellt werden, der Looper.prepare () nicht aufgerufen hat.

81

Ich habe eine Aktivität und darin habe ich eine Klasse.

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

In meinem DynamicText Java habe ich diesen 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) {

    }
}

Ich bekomme:

FEHLER / AndroidRuntime (5176): Auslöser: java.lang.RuntimeException: Es kann kein Handler in einem Thread erstellt werden, der Looper.prepare () nicht aufgerufen hat.

Wie kann ich mit diesem Fehler umgehen?

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
lacas
quelle
Können Sie den vollständigen Stack-Trace veröffentlichen? Sie scheinen eine UI-Methode aus dem Hintergrund-Thread oder so etwas aufzurufen.
Alexanderblom
1
Dies wird das Problem im Detail erklären.
Mjosh

Antworten:

146

Der Fehler ist selbsterklärend ... doInBackground()läuft auf einem Hintergrund-Thread, der, da er nicht als Schleife gedacht ist, nicht mit a verbunden ist Looper.

Sie möchten höchstwahrscheinlich überhaupt keinen Handler direkt instanziieren ... unabhängig davon, welche Daten Ihre doInBackground()Implementierung zurückgibt, werden diese onPostExecute()an den UI-Thread ausgeführt.

   mActivity = ThisActivity.this; 

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

HINZUGEFÜGT NACH DER IN FRAGE ERSCHEINENDEN STACKTRACE:

Sieht so aus, als würden Sie versuchen, einen AsyncTaskvon einem GL-Rendering-Thread aus zu starten. Tun Sie das nicht, denn sie werden es auch nie tun Looper.loop(). AsyncTasks sind wirklich so konzipiert, dass sie nur über den UI-Thread ausgeführt werden können.

Die am wenigsten störende Lösung wäre wahrscheinlich, Activity.runOnUiThread()mit einem Anruf anzurufen Runnable, der Ihren Startschuss gibt AsyncTask.

Reuben Scratton
quelle
1
Die Antwort ist völlig richtig. In meinem Fall musste ich jedoch nur einige Toasts (die versuchen, auf dem UI-Thread ausgeführt zu werden) aus meiner benutzerdefinierten FtpUpload AsyncTask-Klasse und voila entfernen.
Josh
gleicher Fehler wird mir kommen , ich bin confuse wie es zu lösen las i Beschreibung ist aber nicht immer , wie es mir zu tun Code jedermann geben snippest bitte
Android ist alles für mich
32

Alle obigen Antworten sind richtig, aber ich denke, dies ist das einfachste mögliche Beispiel:

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

Dadurch wird ein Fortschrittsbalken im UI-Thread von einem völlig anderen Thread aktualisiert, der über die post () -Methode des in der Aktivität deklarierten Handlers übergeben wird.

Ich hoffe es hilft!

Lisandro
quelle
22

Auf diese Weise erstellen Sie einen Handler im Hintergrund-Thread

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();
    }
Ayman Mahgoub
quelle
Löst nicht nur das Problem, sondern ist auch sehr erklärend. Etwas Problemteig. Wie sich die Struktur ändert, wenn removeCallbacksund quitwann Workdies getan wird, aber keine Verzögerung erreicht wird. Weil die Arbeit länger dauern kann als diese vordefinierte Verzögerung.
Farid
12

Activity.runOnUiThread()funktioniert bei mir nicht Ich habe dieses Problem umgangen, indem ich auf diese Weise einen regulären Thread erstellt habe:

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

und rufen Sie es vom GL-Update folgendermaßen auf:

new PullTasksThread().start();
Eli
quelle
Diese Lösung hat bei mir funktioniert, als ich sie vom GL aus aufgerufen habe, aber Sie müssen sicher sein, dass Sie Toasts on run-Methode nicht aufrufen !! AsyncTask hat nicht funktioniert und es vom GL aufgerufen. Vielen Dank!
Alberto M.
Funktioniert hervorragend für mich beim Ersetzen einer AsyncTask. Vielen Dank!
IgorGanapolsky
5

Versuchen Sie, Ihre asyntask über den UI-Thread auszuführen. Ich war mit diesem Problem konfrontiert, als ich nicht dasselbe tat!

user2560131
quelle
3

Versuche dies

    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.                                     
                            }
                        });
Marcos Militão
quelle
1
Versuchen Sie, wenig Erklärung hinzuzufügen. Nur-Code-Antworten werden auf SO nicht sehr geschätzt.
Alexei