Як відобразити тост із фонової нитки на Android?


Відповіді:


246

Ви можете зробити це, зателефонувавши методу Activity' runOnUiThreadіз своєї нитки:

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

Я не впевнений, що розумію, як це зробити. У мене є наявна публічна недійсна версія (). Я спробував поставити цей код туди. Я знаю, що це неправильно, тому що це не спрацювало, але я дійсно застряг.
SwimBikeRun

14
Чи передається "активність" не-ui-потоку в його конструкторі? Який правильний спосіб отримати об’єкт активності, який ви використовуєте, з окремого потоку?
snapfractalpop

Встановіть на Threadпосилання об'єкта до Activityв Activity«з onResume. Зніміть його в Activity's onPause. Робіть обидва під synchronizedзамком, що Activityі Threadповажають.
JohnnyLambada

5
іноді немає доступу до Activityпримірника, ви можете використовувати простий клас помічників, дивіться тут: stackoverflow.com/a/18280318/1891118
Олексій К.

5
Зазвичай я вважаю, що це MyActivity.this.runOnUiThread()працює чудово зсередини внутрішнього Thread/ AsyncTask.
Ентоні Аткінсон

62

Мені подобається, що у своїй діяльності є метод, під назвою showToastякого я можу зателефонувати з будь-якого місця ...

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

Тоді я найчастіше називаю це зсередини MyActivityна будь-якій такій темі ...

showToast(getString(R.string.MyMessage));

3
Дякую, я зараз додаю цю більшість заходів.
Джин Майєрс

1
Для TOAST завжди використовуйте контекст програми, а не контекст діяльності!
Yousha Aleayoub

1
@YoushaAleayoub чому?
OneWorld

1
@OneWorld, докази: 1- Для повідомлення про тости Посібник Google Dev використовує контекст програми та прямо говорить про те, щоб використовувати його. 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 У ваших посиланнях багато дискусій та здогадів. Наприклад, RomainGuy каже, що у вашому доказі немає витоку пам'яті. 4. Деякі з посилань є з перших днів Android в 2009 році. Також в інших посиланнях люди кажуть, що ви можете використовувати обидва контексти. Діяльність та застосування Можливо, у вас є більш сучасні докази, засновані на реальних доказах? У вас є посилання на 1?
OneWorld

28

Це схоже на інші відповіді, однак оновлені для нових доступних apis та набагато чистіших. Крім того, не передбачає, що ви перебуваєте в контексті активності.

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

Коли у вас контекст не є діяльністю, це ідеальна відповідь. Дуже дякую!
франкас

17

Один із підходів, який працює майже з будь-якого місця, в тому числі з місць, де у вас немає Activityабо View, - це схопити Handlerдо головної нитки і показати тост:

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

Перевага такого підходу полягає в тому, що він працює з будь-якими Context, включаючи Serviceі Application.


10

Як це чи це , з a, Runnableщо показує Toast. А саме,

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

6

Іноді вам доводиться надсилати повідомлення від іншого Threadдо потоку інтерфейсу користувача. Цей тип сценарію виникає, коли ви не можете виконати операції Network / IO на потоці інтерфейсу.

Нижче на прикладі обробляється цей сценарій.

  1. У вас є нитка інтерфейсу користувача
  2. Вам потрібно запустити операцію вводу-виводу, а значить, ви не можете запускати Runnableпо потоку інтерфейсу користувача Тож опублікуйте свій Runnableобробник наHandlerThread
  3. Отримайте результат Runnableі відправте його назад у потік інтерфейсу та покажіть Toastповідомлення.

Рішення:

  1. Створіть HandlerThread і запустіть його
  2. Створіть обробник за допомогою Looper з HandlerThread:requestHandler
  3. Створіть обробник за допомогою Looper з Main Thread: responseHandlerта замініть їїhandleMessage метод
  4. postRunnableзадача поrequestHandler
  5. Усередині Runnableзавдання, виклик sendMessageнаresponseHandler
  6. Цей sendMessageрезультат виклику handleMessageв responseHandler.
  7. Отримати атрибути з Messageта обробити його, оновити інтерфейс користувача

Приклад коду:

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

Корисні статті:

додатки handlerthreads-і-чому-ви-повинні-використовуєте-їм-у-ваших андроїд

android-looper-handler-handlerthread-i


5
  1. Отримати екземпляр і використовувати UI Thread Handler handler.sendMessage();
  2. post()Метод викликуhandler.post();
  3. runOnUiThread()
  4. view.post()

3

Ви можете використовувати Looperдля надсилання Toastповідомлення. Перейдіть за цим посиланням для отримання детальної інформації.

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

і це називається у вашій нитці. Контекст може Activity.getContext()отримуватись від того, що Activityви повинні показати тост.


2

Я зробив такий підхід, грунтуючись на відповіді міжард:

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

Добре працював для мене.


0

Я зіткнувся з тією ж проблемою:

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.

Перед: функція onCreate

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

Після: функція onCreate

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

це спрацювало.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.