Frage Kann Handler innerhalb des Threads nicht erstellen, 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)

767
2017-10-06 17:18


Ursprung


Antworten:


Sie rufen es von einem Arbeitsthread an. Sie müssen anrufen Toast.makeText() (und die meisten anderen Funktionen, die sich mit der Benutzeroberfläche befassen) aus dem Hauptthread heraus. Sie könnten zum Beispiel einen Handler verwenden.

Sieh nach oben Mit dem UI-Thread kommunizieren 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:

Du könntest einen benutzen AsyncTask, das funktioniert gut für die meisten Dinge, die im Hintergrund laufen. Es hat Haken, die Sie aufrufen können, um den Fortschritt anzuzeigen, und wenn es fertig ist.

Du könntest auch benutzen Activity.runOnUiThread ().


541
2017-10-06 17:20



Sie müssen anrufen Toast.makeText(...) aus dem UI-Thread:

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

Dies wird von kopiert ein weiteres (Duplikat) SO Antwort.


750
2018-03-22 02:11



UPDATE - 2016

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

Beginnen Sie mit der Rückkehr Observable von Ihrer bestehenden Methode.

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

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

Benutze 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ß, dass ich ein bisschen spät bin, aber hier geht es. Android arbeitet grundsätzlich an zwei Threadtypen, nämlich UI-Thread und Hintergrundfaden. Laut Android-Dokumentation -

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

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

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

Ich werde es anhand des Codebeispiels erläutern:

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. Threads standardmäßig tun   keine ihnen zugeordnete Nachrichtenschleife; um einen zu erstellen, rufe an   prepare () in dem Thread, der die Schleife ausführen soll, und dann loop () to   Lassen Sie es Nachrichten 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

Mit AsyncTask können Sie asynchrone Arbeiten an Ihrem Benutzer ausführen   Schnittstelle. Es führt die Blockierungsoperationen in einem Worker-Thread und aus   Anschließend werden die Ergebnisse im UI-Thread veröffentlicht, ohne dass Sie dies tun müssen   Handhaben Sie Fäden 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 Runnable-Objekte senden und verarbeiten   verknüpft mit der MessageQueue eines Threads.

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

412
2018-06-02 19:32



Versuchen Sie dies, wenn Sie RuntimeException wegen Looper nicht vor dem Handler erstellt sehen.

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

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

65
2018-06-13 07:26



Ich stieß auf das gleiche Problem, und hier habe ich es behoben:

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
2017-11-30 19:35



Grund für einen Fehler:

Worker-Threads sind für Hintergrundaufgaben gedacht, und Sie können nichts auf der Benutzeroberfläche innerhalb eines Worker-Threads anzeigen, es sei denn, Sie rufen eine Methode auf runOnUiThread. Wenn Sie versuchen, auf dem UI-Thread etwas anzuzeigen, ohne runOnUiThread aufzurufen, wird a angezeigt java.lang.RuntimeException.

Also, wenn du in einem bist activity aber rufen Toast.makeText() aus dem Worker-Thread:

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 anzeigen UI thread seit du es drinnen rufst runOnUiThread Methode. Also nicht mehr java.lang.RuntimeException.


32
2018-05-16 07:40



Toast.makeText() sollte von Main / UI-Thread aufgerufen werden. Looper.getMainLooper() hilft Ihnen, es zu erreichen:

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

Ein Vorteil dieser Methode besteht darin, dass Sie sie auch in Nicht-Aktivitätsklassen (oder ohne Kontext) verwenden können.


25
2018-01-24 00:27



Ich habe diesen Fehler bekommen, bis ich folgendes getan habe.

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 das zu einer Singleton-Klasse gemacht:

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
2017-11-20 13:09