Wie zeigt man einen Toast aus einem Hintergrund-Thread auf Android an?

Antworten:

246

Sie können es tun , indem sie einen Aufruf Activity‚s runOnUiThreadMethode von Thread:

activity.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
    }
});
Lauri Lehtinen
quelle
Ich bin mir nicht sicher, wie ich das machen soll. Ich habe meine bestehende öffentliche Leere run (). Ich habe versucht, diesen Code dort abzulegen. Ich weiß, dass das nicht richtig ist, weil es nicht funktioniert hat, aber ich stecke wirklich fest.
SwimBikeRun
14
Wird "Aktivität" in seinem Konstruktor an den Nicht-UI-Thread übergeben? Was ist der richtige Weg, um das von Ihnen verwendete Aktivitätsobjekt aus dem separaten Thread abzurufen?
Snapfractalpop
Stellen Sie die ThreadObjektreferenz auf die Activityin den Activity's ein onResume. Deaktivieren Sie es in den Activity's onPause. Tun Sie beides unter einem synchronizedSchloss, das sowohl das Activityals auch Threadrespektiert.
Johnny Lambada
5
Manchmal gibt es keinen Zugriff auf die ActivityInstanz. Sie können stattdessen eine einfache Hilfsklasse
Oleksii K.
5
Ich habe normalerweise festgestellt, dass das MyActivity.this.runOnUiThread()innerhalb eines inneren Thread/ gut funktioniert AsyncTask.
Anthony Atkinson
61

Ich möchte eine Methode in meiner Aktivität haben, showToastdie ich von überall aus aufrufen kann ...

public void showToast(final String toast)
{
    runOnUiThread(() -> Toast.makeText(MyActivity.this, toast, Toast.LENGTH_SHORT).show());
}

Ich rufe es dann am häufigsten von innen MyActivityin einem Thread wie diesem auf ...

showToast(getString(R.string.MyMessage));
mjaggard
quelle
3
Danke, ich füge jetzt die meisten Aktivitäten hinzu.
Gene Myers
1
Verwenden Sie für TOAST immer den Anwendungskontext, nicht den Aktivitätskontext!
Yousha Aleayoub
1
@ YoushaAleayoub warum?
OneWorld
1
@OneWorld, Beweise: 1- Für eine Toastnachricht verwendet der Google Dev Guide den Anwendungskontext und sagt ausdrücklich, dass er verwendet werden soll. 2- stackoverflow.com/a/4128799/1429432 3- stackoverflow.com/a/10347346/1429432 4- groups.google.com/d/msg/android-developers/3i8M6-wAIwM/…
Yousha Aleayoub
@YoushaAleayoub In den von Ihnen bereitgestellten Links wird viel diskutiert und geraten. Zum Beispiel sagt RomainGuy, dass Ihr Beweis Nr. 1 kein Speicherleck enthält. 4. Einige der Links stammen aus den Anfängen von Android im Jahr 2009. In den anderen Links wird auch gesagt, dass Sie beide Kontexte verwenden können. Aktivität und Anwendung. Vielleicht haben Sie einen aktuelleren echten evidenzbasierten Beweis? Hast du einen Link für 1?
OneWorld
28

Dies ähnelt anderen Antworten, wurde jedoch für neue verfügbare APIs und viel sauberer aktualisiert. Es wird auch nicht davon ausgegangen, dass Sie sich in einem Aktivitätskontext befinden.

public class MyService extends AnyContextSubclass {

    public void postToastMessage(final String message) {
        Handler handler = new Handler(Looper.getMainLooper());

        handler.post(new Runnable() {

            @Override
            public void run() {
                Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
            }
        });
    }
}
ChrisCM
quelle
Wenn der Kontext, den Sie haben, keine Aktivität ist, ist dies die perfekte Antwort. Vielen Dank!
Francas
17

Ein Ansatz, der von nahezu jedem Ort aus funktioniert, auch von Orten, an denen Sie kein Activityoder haben View, besteht darin, einen Handlerzum Hauptfaden zu greifen und den Toast zu zeigen:

public void toast(final Context context, final String text) {
  Handler handler = new Handler(Looper.getMainLooper());
  handler.post(new Runnable() {
    public void run() {
      Toast.makeText(context, text, Toast.DURATION_LONG).show();
    }
  });
}

Der Vorteil dieses Ansatzes ist, dass er mit jedem funktioniert Context, einschließlich Serviceund Application.

Mike Laren
quelle
10

Wie dies oder das , mit ein , Runnabledass zeigt die Toast. Nämlich,

Activity activity = // reference to an Activity
// or
View view = // reference to a View

activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        showToast(activity);
    }
});
// or
view.post(new Runnable() {
    @Override
    public void run() {
        showToast(view.getContext());
    }
});

private void showToast(Context ctx) {
    Toast.makeText(ctx, "Hi!", Toast.LENGTH_SHORT).show();
}
yanchenko
quelle
6

Manchmal müssen Sie eine Nachricht von einem anderen Threadan den UI-Thread senden . Diese Art von Szenario tritt auf, wenn Sie keine Netzwerk- / E / A-Vorgänge auf dem UI-Thread ausführen können.

Das folgende Beispiel behandelt dieses Szenario.

  1. Sie haben UI-Thread
  2. Sie müssen den E / A-Vorgang starten und können daher nicht Runnableauf dem UI-Thread ausgeführt werden. Also poste deinen RunnableHandler aufHandlerThread
  3. Holen Sie sich das Ergebnis von Runnableund senden Sie es an den UI-Thread zurück und zeigen Sie eine ToastNachricht an.

Lösung:

  1. Erstellen Sie einen HandlerThread und starten Sie ihn
  2. Erstellen Sie einen Handler mit Looper aus HandlerThread:requestHandler
  3. Erstellen Sie einen Handler mit Looper aus dem Hauptthread: responseHandlerund überschreiben Sie die handleMessageMethode
  4. posteine RunnableAufgabe aufrequestHandler
  5. RunnableRufen Sie innerhalb der Aufgabe sendMessageanresponseHandler
  6. Dieser sendMessageErgebnisaufruf von handleMessagein responseHandler.
  7. Holen Sie sich Attribute aus dem Messageund verarbeiten Sie es, aktualisieren Sie die Benutzeroberfläche

Beispielcode:

    /* Handler thread */

    HandlerThread handlerThread = new HandlerThread("HandlerThread");
    handlerThread.start();
    Handler requestHandler = new Handler(handlerThread.getLooper());

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Runnable on HandlerThread is completed and got result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    for ( int i=0; i<5; i++) {
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                try {

                    /* Add your business logic here and construct the 
                       Messgae which should be handled in UI thread. For 
                       example sake, just sending a simple Text here*/

                    String text = "" + (++rId);
                    Message msg = new Message();

                    msg.obj = text.toString();
                    responseHandler.sendMessage(msg);
                    System.out.println(text.toString());

                } catch (Exception err) {
                    err.printStackTrace();
                }
            }
        };
        requestHandler.post(myRunnable);
    }

Nützliche Artikel:

handlerthreads-und-warum-du-solltest-sie-in-deinen-android-apps verwenden

android-looper-handler-handlerthread-i

Ravindra Babu
quelle
5
  1. Holen Sie sich die UI Thread Handler-Instanz und verwenden Sie sie handler.sendMessage();
  2. post()Methode aufrufenhandler.post();
  3. runOnUiThread()
  4. view.post()
Kerwin Sie
quelle
3

Sie können Looperzum Senden von ToastNachrichten verwenden. Gehen Sie über diesen Link für weitere Details.

public void showToastInThread(final Context context,final String str){
    Looper.prepare();
    MessageQueue queue = Looper.myQueue();
    queue.addIdleHandler(new IdleHandler() {
         int mReqCount = 0;

         @Override
         public boolean queueIdle() {
             if (++mReqCount == 2) {
                  Looper.myLooper().quit();
                  return false;
             } else
                  return true;
         }
    });
    Toast.makeText(context, str,Toast.LENGTH_LONG).show();      
    Looper.loop();
}

und es heißt in deinem Thread. Der Kontext kann Activity.getContext()von dem stammen, dass ActivitySie den Toast zeigen müssen.

Vinoj John Hosan
quelle
2

Ich habe diesen Ansatz basierend auf der Antwort von mjaggard gemacht:

public static void toastAnywhere(final String text) {
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
        public void run() {
            Toast.makeText(SuperApplication.getInstance().getApplicationContext(), text, 
                    Toast.LENGTH_LONG).show();
        }
    });
}

Hat gut für mich funktioniert.

Engelo Polotto
quelle
0

Ich bin auf das gleiche Problem gestoßen:

E/AndroidRuntime: FATAL EXCEPTION: Thread-4
              Process: com.example.languoguang.welcomeapp, PID: 4724
              java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
                  at android.widget.Toast$TN.<init>(Toast.java:393)
                  at android.widget.Toast.<init>(Toast.java:117)
                  at android.widget.Toast.makeText(Toast.java:280)
                  at android.widget.Toast.makeText(Toast.java:270)
                  at com.example.languoguang.welcomeapp.MainActivity$1.run(MainActivity.java:51)
                  at java.lang.Thread.run(Thread.java:764)
I/Process: Sending signal. PID: 4724 SIG: 9
Application terminated.

Vorher: onCreate-Funktion

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
    }
});
thread.start();

Nachher: ​​onCreate-Funktion

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
    }
});

es funktionierte.

Languoguang
quelle