it-swarm.com.de

Handler kann nicht in Thread erstellt werden, der Looper.prepare () nicht aufgerufen hat

Was bedeutet die folgende Ausnahme? wie kann ich es reparieren?

Dies ist der Code:

Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);

Dies ist die Ausnahme:

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.<init>(Toast.Java:68)
     at Android.widget.Toast.makeText(Toast.Java:231)
830
michael

Sie nennen es von einem Arbeitsthread aus. Sie müssen Toast.makeText() (und die meisten anderen Funktionen, die sich auf die Benutzeroberfläche beziehen) vom Haupt-Thread aus aufrufen. Sie könnten beispielsweise einen Handler verwenden.

Nachschlagen Kommunizieren mit dem UI-Thread in der Dokumentation. In einer Nussschale:

// Set this up in the UI thread.

mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message message) {
        // This is where you do your work in the UI thread.
        // Your worker tells you in the message what to do.
    }
};

void workerThread() {
    // And this is how you call it from the worker thread:
    Message message = mHandler.obtainMessage(command, parameter);
    message.sendToTarget();
}

Andere Optionen:

Sie könnten eine AsyncTask verwenden, die für die meisten Dinge im Hintergrund gut funktioniert. Es gibt Haken, die Sie anrufen können, um den Fortschritt anzuzeigen und wann es fertig ist.

Sie können auch Activity.runOnUiThread () verwenden.

596
EboMike

Sie müssen Toast.makeText(...) vom UI-Thread aus aufrufen:

activity.runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
  }
});

Dies wird kopiert von einer anderen (Duplikat) SO - Antwort .

786
Jacob Marble

UPDATE - 2016

Die beste Alternative ist, RxAndroid (spezifische Bindungen für RxJava) für P in MVP zu verwenden, um Daten zu übernehmen.

Beginnen Sie mit der Rückgabe von Observable aus Ihrer vorhandenen Methode.

private Observable<PojoObject> getObservableItems() {
    return Observable.create(subscriber -> {

        for (PojoObject pojoObject: pojoObjects) {
            subscriber.onNext(pojoObject);
        }
        subscriber.onCompleted();
    });
}

Verwenden Sie dieses Observable so -

getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
    @Override
    public void onCompleted() {
        // Print Toast on completion
    }

    @Override
    public void onError(Throwable e) {}

    @Override
    public void onNext(PojoObject pojoObject) {
        // Show Progress
    }
});
}

------------------------------------------------ -------------------------------------------------- --------------------------------

Ich weiß, ich bin etwas spät dran, aber hier geht es weiter ... __ Android arbeitet grundsätzlich an zwei Thread-Typen, nämlich UI-Threadund Hintergrund-Thread. Laut Android-Dokumentation - 

Greifen Sie nicht außerhalb des UI-Threads auf das Android UI-Toolkit zu, um dieses Problem zu beheben. Android bietet mehrere Möglichkeiten, auf den UI-Thread von anderen Threads zuzugreifen. Hier ist eine Liste von Methoden, die helfen können:

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

Nun gibt es verschiedene Methoden, um dieses Problem zu lösen. 

Ich werde es anhand eines Codebeispiels erklären:

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

Klasse, die zum Ausführen einer Nachrichtenschleife für einen Thread verwendet wird. Standardmäßig tun Threads keine Nachrichtenschleife zugeordnet ist; Um einen zu erstellen, rufen Sie prepare () in dem Thread, der die Schleife ausführen soll, und dann Schleife () an lassen Sie Meldungen verarbeiten, bis die Schleife gestoppt ist.

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 ermöglicht Ihnen die asynchrone Arbeit an Ihrem Benutzer Schnittstelle. Es führt die Blockierungsvorgänge in einem Arbeitsthread und .__ aus. veröffentlicht dann die Ergebnisse im UI-Thread, ohne dass Sie Handle Threads und/oder Handler selbst.

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
    }
}

Handler

Mit einem Handler können Sie Message- und Runable-Objekte senden und verarbeiten der MessageQueue eines Threads zugeordnet ist.

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;
    }
});
419
mjosh

Versuchen Sie dies, wenn Sie RuntimeException aufgrund von Looper sehen, der nicht vor dem Handler vorbereitet wurde.

Handler handler = new Handler(Looper.getMainLooper()); 

handler.postDelayed(new Runnable() {
  @override
  void run() {
  // Run your task here
  }
}, 1000 );
76
Khulja Sim Sim

Toast.makeText() sollte vom Main/UI-Thread aufgerufen werden. Looper.getMainLooper () hilft Ihnen dabei:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
    }
});

Ein Vorteil dieser Methode ist, dass Sie sie auch in Klassen ohne Aktivität (oder ohne Kontext) verwenden können.

57
Sa Qada

Ich bin auf das gleiche Problem gestoßen und hier ist es, wie ich es behoben habe:

private final class UIHandler extends Handler
{
    public static final int DISPLAY_UI_TOAST = 0;
    public static final int DISPLAY_UI_DIALOG = 1;

    public UIHandler(Looper looper)
    {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg)
    {
        switch(msg.what)
        {
        case UIHandler.DISPLAY_UI_TOAST:
        {
            Context context = getApplicationContext();
            Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
            t.show();
        }
        case UIHandler.DISPLAY_UI_DIALOG:
            //TBD
        default:
            break;
        }
    }
}

protected void handleUIRequest(String message)
{
    Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
    msg.obj = message;
    uiHandler.sendMessage(msg);
}

Um den UIHandler zu erstellen, müssen Sie Folgendes ausführen:

    HandlerThread uiThread = new HandlerThread("UIHandler");
    uiThread.start();
    uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());

Hoffe das hilft.

39
ChicoBird

Grund für einen Fehler:

Worker-Threads sind für Hintergrundaufgaben gedacht, und Sie können auf der Benutzeroberfläche innerhalb eines Worker-Threads nichts anzeigen, wenn Sie keine Methode wie runOnUiThread aufrufen. Wenn Sie versuchen, im UI-Thread etwas anzuzeigen, ohne runOnUiThread aufzurufen, wird ein Java.lang.RuntimeException angezeigt.

Wenn Sie sich in einer activity befinden, aber Toast.makeText() vom Worker-Thread aus aufrufen, führen Sie Folgendes aus:

runOnUiThread(new Runnable() 
{
   public void run() 
   {
      Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();    
   }
}); 

Der obige Code stellt sicher, dass Sie die Toast-Nachricht in einem UI thread anzeigen, da Sie sie in der runOnUiThread-Methode aufrufen. Also kein Java.lang.RuntimeException mehr.

32
My God

Ich habe diesen Fehler erhalten, bis ich Folgendes tat.

public void somethingHappened(final Context context)
{
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(
        new Runnable()
        {
            @Override
            public void run()
            {
                Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
            }
        }
    );
}

Und machte dies zu einer Einzelklasse:

public enum Toaster {
    INSTANCE;

    private final Handler handler = new Handler(Looper.getMainLooper());

    public void postMessage(final String message) {
        handler.post(
            new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
                        .show();
                }
            }
        );
    }

}
21
EpicPandaForce

das ist, was ich tat.

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast(...);
    }
});

Visuelle Komponenten sind für Änderungen von externen Threads "gesperrt". Da der Toast auf dem Hauptbildschirm, der vom Haupt-Thread verwaltet wird, angezeigt wird, müssen Sie diesen Code in diesem Thread ausführen :)

19
eiran

Dies liegt daran, dass Toast.makeText () von einem Arbeitsthread aus aufgerufen wird. Es sollte so vom Haupt-UI-Thread aufgerufen werden 

runOnUiThread(new Runnable() {
      public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
      }
 });
8

Die Antwort von ChicoBird funktionierte für mich. Die einzige Änderung, die ich vorgenommen habe, war die Erstellung des UI-Handlers, wo ich etwas tun musste 

HandlerThread uiThread = new HandlerThread("UIHandler");

Eclipse weigerte sich, etwas anderes zu akzeptieren. Macht Sinn, denke ich.

Auch uiHandler ist eindeutig eine irgendwo definierte Klasse global. Ich behaupte immer noch nicht zu verstehen, wie Android dies tut und was los ist, aber ich bin froh, dass es funktioniert. Jetzt werde ich weiter studieren und sehen, ob ich verstehen kann, was Android macht und warum man all diese Reifen und Schleifen durchlaufen muss. Danke für die Hilfe ChicoBird.

7
Brian Reinhold
 runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
            }
        });
5
Coldfin Lab

Für Rxjava- und RxAndroid-Benutzer:

public static void shortToast(String msg) {
    Observable.just(msg)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(message -> {
                Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
            });
}
4
Geng Jiawen

Ich hatte das gleiche Problem, als meine Callbacks versuchten, ein Dialogfeld anzuzeigen. 

Ich habe es mit dedizierten Methoden in der Activity - auf der Activity Instanz Member Level - gelöst, die runOnUiThread(..) verwenden

public void showAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
        }
    });
}

public void dismissAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
                return;
            }
            mAuthProgressDialog.dismiss();
        }
    });
}
4
Gene Bo

Wunderbare Kotlin-Lösung:

runOnUiThread {
    // Add your ui thread code here
}
1
jungledev

Um ein Dialogfeld oder einen Toaster in einem Thread anzuzeigen, verwenden Sie am besten das Aktivitätsobjekt.

Zum Beispiel:

new Thread(new Runnable() {
    @Override
    public void run() {
        myActivity.runOnUiThread(new Runnable() {
            public void run() {
                myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
                myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                myActivity.this.processingWaitDialog.setMessage("abc");
                myActivity.this.processingWaitDialog.setIndeterminate(true);
                myActivity.this.processingWaitDialog.show();
            }
        });
        expenseClassify.serverPost(
                new AsyncOperationCallback() {
                    public void operationCompleted(Object sender) {
                        myActivity.runOnUiThread(new Runnable() {
                            public void run() {
                                if (myActivity.this.processingWaitDialog != null 
                                        && myActivity.this.processingWaitDialog.isShowing()) {
                                    myActivity.this.processingWaitDialog.dismiss();
                                    myActivity.this.processingWaitDialog = null;
                                }
                            }
                        }); // .runOnUiThread(new Runnable()
...
1
Liwen Zhao

Toast, AlertDialogs muss auf dem UI-Thread ausgeführt werden. Sie können Asynctask verwenden, um sie in der Android-Entwicklung ordnungsgemäß zu verwenden. In einigen Fällen müssen wir jedoch die Timeouts anpassen. Daher verwenden wir Threads. In Threads können wir jedoch keine Toast-Alertdialoge verwenden, wie wir sie in AsyncTask verwenden. Deshalb benötigen wir separate Handler, um diese aufzurufen.

public void onSigned() {
    Thread thread = new Thread(){
        @Override
        public void run() {
            try{
                sleep(3000);
                Message message = new Message();
                message.what = 2;
                handler.sendMessage(message);
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    };
    thread.start();
}

in obigem Beispiel möchte ich meinen Thread in 3 Sekunden schlafen und nachdem ich eine Toast-Nachricht anzeigen möchte, wird dies in Ihrem mainthread -Implementhandler ausgeführt.

handler = new Handler() {
       public void handleMessage(Message msg) {
           switch(msg.what){
              case 1:
              Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
              break;
           }
           super.handleMessage(msg);
       }
};

Ich habe hier switch case verwendet, denn wenn Sie unterschiedliche Meldungen auf dieselbe Weise anzeigen müssen, können Sie switch case in der Handler-Klasse verwenden ... Ich hoffe, das hilft Ihnen

0
Ashana.Jackol

Dies geschieht normalerweise, wenn im Hauptthread etwas von einem Hintergrundthread aus aufgerufen wird. Schauen wir uns zum Beispiel ein Beispiel an.

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


@Override
protected Void doInBackground(Void... voids) {
        textView.setText("Any Text");
        return null;
    }
}

Im obigen Beispiel setzen wir Text in der Textansicht, die sich im Haupt-UI-Thread der doInBackground () -Methode befindet, die nur für einen Worker-Thread ausgeführt wird.

0
Handler handler2;  
Thread second_thread=new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                handler2=new Handler();
            }
        });
        second_thread.start();

Handler2 verwendet jetzt wahrscheinlich einen anderen Thread, um die Nachrichten als den Haupt-Thread zu behandeln.

0
Tarasantan

rufen Sie zuerst Looper.prepare() und dann Toast.makeText().show() auf. Letzter Aufruf Looper.loop() wie:

Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
0
Hasan A Yousef

Ich hatte das gleiche Problem und habe es einfach behoben, indem ich den Toast in die onPostExecute () - Überschreibungsfunktion der Asynctask <> setzte und es funktionierte. 

0
alibabaei12