Android: тост в потоке

Как я могу отображать тост сообщения из цепочки?

14 ответов

Решение

Вы можете сделать это, позвонив Activity"s runOnUiThread метод из вашей темы:

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

Мне нравится иметь метод в моей деятельности под названием showToast на который я могу позвонить откуда угодно...

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

Я тогда чаще всего называю это изнутри MyActivity в любой теме, как это...

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

Это похоже на другие ответы, однако обновлено для новых доступных API и намного чище. Кроме того, не предполагается, что вы находитесь в контексте деятельности.

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

Один подход, который работает практически из любого места, в том числе из мест, где у вас нет 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.DURATION_LONG).show();
    }
  });
}

Преимущество этого подхода в том, что он работает с любым Context, в том числе Service а также Application,

Как это или это, с 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();
}

Иногда вам нужно отправить сообщение от другого Thread в поток пользовательского интерфейса. Этот тип сценария возникает, когда вы не можете выполнить операции Network/IO в потоке пользовательского интерфейса.

Ниже пример обрабатывает этот сценарий.

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

Решение:

  1. Создайте HandlerThread и запустите его
  2. Создать обработчик с Looper из HandlerThread: requestHandler
  3. Создайте обработчик с Looper из основного потока: responseHandler и переопределить handleMessage метод
  4. post Runnable задание на 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-приложений

Android-петлителя-обработчик-handlerthread-я

  1. Получить экземпляр обработчика пользовательского интерфейса и использовать handler.sendMessage();
  2. Вызов post() метод handler.post();
  3. runOnUiThread()
  4. view.post()

Ты можешь использовать 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 Вы должны показать тост.

Код Kotlin с runOnUiThread

runOnUiThread(
        object : Runnable {
            override fun run() {
                Toast.makeText(applicationContext, "Calling from runOnUiThread()", Toast.LENGTH_SHORT)  
            }
        }
)

Я сделал этот подход, основываясь на ответе Мьяггарда:

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

Работал хорошо для меня.

Я столкнулся с той же проблемой:

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

это сработало.

Java 11:

      var handler = new Handler(Looper.getMainLooper);
handler.post(() -> Toast.makeText(your_context, "Hi!", Toast.LENGTH_SHORT).show());

Однако лямбды доступны в java 8. var представлен в java 11.

Вопреки почти каждому ответу здесь, Toast#makeTextи НЕ должны работать в потоке пользовательского интерфейса. Единственное требование состоит в том, чтобы он выполнялся в потоке, который вызвал Looper#prepare.

Причина этого в том, что всплывающие уведомления обрабатываются и отображаются ОС, а не приложением. Внутри, Toast#showвызывает системную службу для постановки всплывающего уведомления в очередь.

Это означает, что следующий код действителен

      private static class MyThread extends Thread {
    public Handler handler;

    @Override
    public void run() {
        Looper.prepare();

        handler = new Handler(Looper.myLooper()) {
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };

        Looper.loop()
    }
}

final private MyThread t = new MyThread();
// start and wait for t to start looping

private void onClick() {
    t.handler.post(() -> Toast.makeText(this, "this works", Toast.LENGTH_SHORT).show());
}

Метод onCreate:

      private void toastPublic(final String message){
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
       public void run() {
          Toast.makeText(getBaseContext(),""+message, 
             4 /*Toast.LENGTH_SHORT*/).show();
    }});
}

Далее: использовать внутри Thread

Другие вопросы по тегам