Jak wyświetlić toast z wątku w tle na Androidzie?

Odpowiedzi:

246

Można to zrobić przez wywołanie Activity„s runOnUiThreadmetody w wątku:

activity.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
    }
});
Lauri Lehtinen
źródło
Nie jestem pewien, czy rozumiem, jak to zrobić. Mam istniejący publiczny void run (). Próbowałem tam umieścić ten kod. Wiem, że to nie w porządku, ponieważ nie zadziałało, ale naprawdę utknąłem.
SwimBikeRun
14
Czy „aktywność” jest przekazywana do wątku innego niż ui w jego konstruktorze? Jaki jest właściwy sposób uzyskania obiektu aktywności, którego używasz, z osobnego wątku?
snapfractalpop
Ustaw Threadodniesienie do obiektu Activityw Activity„s onResume. Rozbrojony to w Activity„s onPause. Zrób oba pod synchronizedzamkiem, który zarówno szanuje , jak Activityi Thread.
JohnnyLambada
5
czasami nie ma dostępu do Activityinstancji, możesz zamiast tego użyć prostej klasy pomocniczej, patrz tutaj: stackoverflow.com/a/18280318/1891118
Oleksii K.
5
Zwykle stwierdziłem, że MyActivity.this.runOnUiThread()działa dobrze od wewnątrz Thread/ AsyncTask.
Anthony Atkinson
62

Lubię mieć w swojej działalności metodę o nazwie, showToastktórą mogę wywołać z dowolnego miejsca ...

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

Wtedy najczęściej dzwonię do tego od wewnątrz MyActivityw każdym takim wątku ...

showToast(getString(R.string.MyMessage));
mjaggard
źródło
3
Dzięki, dodam teraz większość działań.
Gene Myers
1
W przypadku TOAST zawsze używaj kontekstu aplikacji, a nie kontekstu działania!
Yousha Aleayoub
1
@YoushaAleayoub dlaczego?
OneWorld
1
@OneWorld, dowody: 1 - w przypadku wyskakującej wiadomości przewodnik Google dla programistów używa kontekstu aplikacji i wyraźnie mówi, aby go używać. 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 W podanych przez Ciebie linkach jest dużo dyskusji i domysłów. Np. RomainGuy mówi, że w twoim dowodzie nie ma wycieku pamięci. 4. Niektóre linki pochodzą z wczesnych dni Androida w 2009 roku. W innych odsyłaczach ludzie mówią również, że można używać obu kontekstów. Aktywność i zastosowanie. Może masz bardziej aktualne dowody oparte na faktach? Czy masz link do 1?
OneWorld
28

Jest to podobne do innych odpowiedzi, jednak zaktualizowane pod kątem nowych dostępnych interfejsów API i znacznie czystsze. Ponadto nie zakłada, że ​​znajdujesz się w kontekście działania.

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
źródło
Kiedy kontekst, który masz, nie jest działaniem, które jest doskonałą odpowiedzią. Wielkie dzięki!
francas
17

Jedną z metod, która działa z dowolnego miejsca, w tym z miejsc, w których nie masz znaku Activitylub View, jest przechwycenie Handlerdo głównego wątku i pokazanie toastu:

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

Zaletą tego podejścia jest to, że działa z dowolnymi Context, w tym Servicei Application.

Mike Laren
źródło
10

Jak ten lub ta , z Runnablektóra pokazuje Toast. Mianowicie,

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
źródło
6

Czasami musisz wysłać wiadomość z innego Threadwątku do wątku interfejsu użytkownika. Ten typ scenariusza występuje, gdy nie można wykonać operacji sieci / we / wy w wątku interfejsu użytkownika.

Poniższy przykład obsługuje ten scenariusz.

  1. Masz wątek interfejsu użytkownika
  2. Musisz rozpocząć operację IO, a zatem nie możesz uruchomić Runnablew wątku interfejsu użytkownika. Więc prześlij swoje zgłoszenie Runnabledo programu obsługiHandlerThread
  3. Pobierz wynik z Runnablei wyślij go z powrotem do wątku interfejsu użytkownika i pokaż Toastwiadomość.

Rozwiązanie:

  1. Utwórz HandlerThread i uruchom go
  2. Utwórz Handler z Looper z HandlerThread:requestHandler
  3. Utwórz Handler with Looper z Main Thread: responseHandleri przesłoń handleMessagemetodę
  4. postRunnablezadanie narequestHandler
  5. Wewnątrz Runnablezadanie, zadzwoń sendMessagenaresponseHandler
  6. To sendMessagewywołanie wyniku handleMessagein responseHandler.
  7. Pobierz atrybuty z Messagei przetwórz je, zaktualizuj interfejs użytkownika

Przykładowy kod:

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

Przydatne artykuły:

handlerthreads-and-Why-you-should-be-using-them-in-your-android-apps

android-looper-handler-handlerthread-i

Ravindra babu
źródło
5
  1. Pobierz instancję obsługi wątków interfejsu użytkownika i użyj handler.sendMessage();
  2. post()Metoda wywołaniahandler.post();
  3. runOnUiThread()
  4. view.post()
Kerwin You
źródło
3

Możesz użyć Looperdo wysłania Toastwiadomości. Przejdź przez ten link, aby uzyskać więcej informacji.

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

i jest nazywany w twoim wątku. Kontekst może wynikać Activity.getContext()z tego, Activityże musisz pokazać toast.

Vinoj John Hosan
źródło
2

Zrobiłem to na podstawie odpowiedzi mjaggarda:

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

Pracował dobrze dla mnie.

Ângelo Polotto
źródło
0

Napotkałem ten sam problem :

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.

Przed: funkcja onCreate

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

Po: funkcja onCreate

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

zadziałało.

Languoguang
źródło