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 в потоке пользовательского интерфейса.
Ниже пример обрабатывает этот сценарий.
- У вас есть тема интерфейса
- Вы должны начать операцию ввода-вывода и, следовательно, вы не можете запустить
Runnable
в пользовательском интерфейсе Так разместите свойRunnable
обрабатывать наHandlerThread
- Получить результат от
Runnable
и отправить его обратно в поток пользовательского интерфейса и показатьToast
сообщение.
Решение:
- Создайте HandlerThread и запустите его
- Создать обработчик с Looper из
HandlerThread
:requestHandler
- Создайте обработчик с Looper из основного потока:
responseHandler
и переопределитьhandleMessage
метод post
Runnable
задание наrequestHandler
- внутри
Runnable
задача, вызовsendMessage
наresponseHandler
- это
sendMessage
результат вызоваhandleMessage
вresponseHandler
, - Получить атрибуты из
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-приложений
- Получить экземпляр обработчика пользовательского интерфейса и использовать
handler.sendMessage();
- Вызов
post()
методhandler.post();
runOnUiThread()
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