[英]How do you display a Toast from a background thread on Android?
You can do it by calling an Activity
's runOnUiThread
method from your thread:您可以通过从您的线程调用Activity
的runOnUiThread
方法来实现:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
I like to have a method in my activity called showToast
which I can call from anywhere...我喜欢在我的活动中有一个名为showToast
的方法,我可以从任何地方调用它...
public void showToast(final String toast)
{
runOnUiThread(() -> Toast.makeText(MyActivity.this, toast, Toast.LENGTH_SHORT).show());
}
I then most frequently call it from within MyActivity
on any thread like this...然后,我最常从MyActivity
在任何像这样的线程上调用它......
showToast(getString(R.string.MyMessage));
This is similar to other answers, however updated for new available apis and much cleaner.这与其他答案类似,但是针对新的可用 API 进行了更新,并且更加清晰。 Also, does not assume you're in an Activity Context.此外,不假设您处于活动上下文中。
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();
}
});
}
}
One approach that works from pretty much anywhere, including from places where you don't have an Activity
or View
, is to grab a Handler
to the main thread and show the toast:一种几乎适用于任何地方(包括没有Activity
或View
)的方法是将Handler
抓取到主线程并显示 Toast:
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();
}
});
}
The advantage of this approach is that it works with any Context
, including Service
and Application
.这种方法的优点是它适用于任何Context
,包括Service
和Application
。
Like this or this , with a Runnable
that shows the Toast
.像这样或这样,带有一个显示Toast
的Runnable
。 Namely,即,
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();
}
Sometimes, you have to send message from another Thread
to UI thread.有时,您必须从另一个Thread
向 UI 线程发送消息。 This type of scenario occurs when you can't execute Network/IO operations on UI thread.当您无法在 UI 线程上执行网络/IO 操作时,就会发生这种情况。
Below example handles that scenario.下面的示例处理这种情况。
Runnable
on UI thread.您必须启动 IO 操作,因此您无法在 UI 线程上运行Runnable
。 So post your Runnable
to handler on HandlerThread
因此,将您的Runnable
到HandlerThread
上的处理程序Runnable
and send it back to UI thread and show a Toast
message.从Runnable
获取结果并将其发送回 UI 线程并显示Toast
消息。Solution:解决方案:
HandlerThread
: requestHandler
从HandlerThread
使用Looper创建一个处理程序: requestHandler
responseHandler
and override handleMessage
method从主线程使用 Looper 创建一个处理程序: responseHandler
并覆盖handleMessage
方法post
a Runnable
task on requestHandler
在requestHandler
上post
一个Runnable
任务Runnable
task, call sendMessage
on responseHandler
在Runnable
任务中,在responseHandler
上调用sendMessage
sendMessage
result invocation of handleMessage
in responseHandler
.这个sendMessage
结果在responseHandler
调用handleMessage
。Message
and process it, update UI从Message
获取属性并进行处理,更新 UISample code:示例代码:
/* 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);
}
Useful articles:有用的文章:
handlerthreads-and-why-you-should-be-using-them-in-your-android-apps handlerthreads-and-why-you-should-be-using-them-in-your-android-apps
android-looper-handler-handlerthread-i android-looper-handler-handlerthread-i
handler.sendMessage();
获取 UI Thread Handler 实例并使用handler.sendMessage();
post()
method handler.post();
调用post()
方法handler.post();
runOnUiThread()
view.post()
You can use Looper
to send Toast
message.您可以使用Looper
发送Toast
消息。 Go through this link for more 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();
}
and it is called in your thread.它在您的线程中被调用。 Context may be Activity.getContext()
getting from the Activity
you have to show the toast. Context 可能是Activity.getContext()
从你必须展示 toast 的Activity
获取。
I made this approach based on mjaggard answer:我根据 mjaggard 回答制定了这种方法:
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();
}
});
}
Worked well for me.对我来说效果很好。
Kotlin Code with runOnUiThread带有 runOnUiThread 的 Kotlin 代码
runOnUiThread(
object : Runnable {
override fun run() {
Toast.makeText(applicationContext, "Calling from runOnUiThread()", Toast.LENGTH_SHORT)
}
}
)
I encountered the same 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.
Before: onCreate function之前:onCreate 函数
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
}
});
thread.start();
After: onCreate function之后:onCreate 函数
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
}
});
it worked.有效。
java 11:爪哇11:
var handler = new Handler(Looper.getMainLooper);
handler.post(() -> Toast.makeText(your_context, "Hi!", Toast.LENGTH_SHORT).show());
Lambdas are available in java 8 though.不过,在 Java 8 中可以使用 Lambda。 var
is introduced in java 11. var
是在 Java 11 中引入的。
Contrary to almost every answer here, Toast#makeText
and Toast#show
do NOT have to run on the UI thread.与此处几乎所有答案相反, Toast#makeText
和Toast#show
不必在 UI 线程上运行。 The only requirement is that it runs on a thread that has called Looper#prepare
.唯一的要求是它在一个名为Looper#prepare
的线程上运行。
The reasons for this is because toasts are handled and rendered by the OS, not the application.这是因为 toast 是由操作系统处理和呈现的,而不是应用程序。 Internally, Toast#show
makes a call to a system service to enqueue the toast.在内部, Toast#show
调用系统服务以将 toast 排队。
This means the following code is valid这意味着下面的代码是有效的
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());
}
Method in onCreate: 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();
}});
}
Next: use in inside Thread下一步:在线程内部使用
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.