How can I display Toast messages from a thread?
This question is related to
android
multithreading
android-toast
You can use Looper
to send Toast
message. 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.
Kotlin Code with runOnUiThread
runOnUiThread(
object : Runnable {
override fun run() {
Toast.makeText(applicationContext, "Calling from runOnUiThread()", Toast.LENGTH_SHORT)
}
}
)
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:
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
.
Sometimes, you have to send message from another Thread
to UI thread. This type of scenario occurs when you can't execute Network/IO operations on UI thread.
Below example handles that scenario.
Runnable
on UI thread. So post your Runnable
to handler on HandlerThread
Runnable
and send it back to UI thread and show a Toast
message.Solution:
HandlerThread
:requestHandler
responseHandler
and override handleMessage
methodpost
a Runnable
task on requestHandler
Runnable
task, call sendMessage
on responseHandler
sendMessage
result invocation of handleMessage
in responseHandler
.Message
and process it, update 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
This is similar to other answers, however updated for new available apis and much cleaner. 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();
}
});
}
}
handler.sendMessage();
post()
method handler.post();
runOnUiThread()
view.post()
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
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
}
});
thread.start();
After: onCreate function
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
}
});
it worked.
Like this or this, with a Runnable
that shows the Toast
.
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();
}
I like to have a method in my activity called showToast
which I can call from anywhere...
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...
showToast(getString(R.string.MyMessage));
I made this approach based on mjaggard answer:
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.
Source: Stackoverflow.com