Indefinite Toast Hack
Hey everyone,
Long time no post. By request, I’m going to give an example / code snippet on how to create a Toast that doesn’t fade away and that lasts for an indefinite amount of time.
So the issue at hand is this: the length of a toast is predefined as either Toast.LENGTH_LONG (~3 sec) or Toast.LENGH_SHORT (~2 sec), and so creating a toast that lasts longer than LENGTH_LONG is not possible without a small hack. And so the example is as follows:
public class LongToast extends Activity { private TextView toast_text; private ImageView image; private Toast toast; private View layout; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // your code ... most likely code that in some way triggers this toast toast = new Toast(this); // example of how to make a custom toast LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); // define some kind of toast_layout.xml file in your res/layout directory and inflate it here layout = inflater.inflate(R.layout.toast_layout, null); image = (ImageView) layout.findViewById(R.id.image_icon); toast_text = (TextView) layout.findViewById(R.id.toast_text); // programmatically set parameters toast.setGravity(Gravity.TOP, 0, 0); toast.setDuration(Toast.LENGTH_SHORT); toast.setView(layout); String text = "I'm a custom toast."; toast_text.setText(text); image.setImageResource(R.icon); // and here is the hack fireLongToast(); } private void fireLongToast() { Thread t = new Thread() { public void run() { int count = 0; try { while (true && count < 10) { toast.show(); sleep(1850); count++; // do some logic that breaks out of the while loop } } catch (Exception e) { Log.e("LongToast", "", e); } } }; t.start(); }
So a few remarks about this example. First I simply set up my custom toast (again, this example can double as an example of how to inflate and define a custom toast… but of course the example will work just as well with a standard toast), but the crux of the example is in the method fireLongToast().
The idea is that we need some kind of way to continuously call the toast.show() method and hence we need to embed our toast in some sort of while() loop that continues to run until we decide to break out of it and effectively stop calling toast.show() and hence end the long toast. We also don’t want to choke up the main UI thread and so we want to do this in the background somehow (otherwise our code will just remain in the while loop and you won’t be able to execute any other operations while the toast is shown), hence we run it in a separate thread. As far as implementation goes, it’s probably smart to have some kind of global boolean that gets toggled in your onCreate() method and which will basically kill the thread (see Stop Thread for more on stopping threads in Java). And finally, putting it into a thread also gives us the added benefit of having a sleep method. For Toasts, typically if you call toast.show() two times one after the other, the effect you get is that your toast will show for the full length both times. In other words, if I do something like:
toast.setDuration(Toast.LENGHT_LONG); for(int i = 0; i < N; i++) { toast.show(); }
Then our toast will remain for N * LENGTH_LONG which is not necessarily what we want. So instead, we cause the thread to sleep for approximately the amount of time equivalent to LENGTH_SHORT in this case, so that we don’t fire too many toasts and this way we are guaranteed that as soon as the boolean gets toggled and we exit the while() loop, we won’t have a whole queue of toasts waiting to get fired.
Finally, one last thing to mention is the added check of count < 10. The 10 in this case is arbitrary, but the idea is in case something happens and that boolean never gets toggled, you don't want to remain in the while loop indefinitely as otherwise your toast will show up indefinitely and you're basically hosed at that point. Instead, when I implement this hack I keep a count of how many times my toast is shown, and I designate some max number of times to show it, so that even in the situation where something messes up and my boolean never gets toggled my code still guarantees that the toast will eventually go away.
Hope this all makes sense and hope this was helpful.
Happy coding.
– jwei
It isn’t safe to touch the UI from background threads. You can get crashes etc. Your background thread should signal the main thread that it should refresh the toast.
It’s probably one of those insidious things that works on some devices but causes problems on others. Gotta love Android.
private void fireLongToast() {
mStopThread = false;
//Log.d(LOG_TAG, “enter fireLongToast()”);
Runnable long_toast_run = new Runnable() {
@Override
public void run() {
try {
while (!mStopThread) {
mToast.show();
Thread.sleep(2500);
}
} catch (Exception e) {
Log.e(LOG_TAG, e.getMessage());
}
mHandler.post(new Runnable() {
public void run() {
mStopThread = true;
mService.stopSelf();
}
});
//Log.d(LOG_TAG, “exited long toast thread”);
}
};
Thread t = new Thread(null, long_toast_run, LOG_TAG
+ ” fireLongToast thread”);
t.start();
}
that is safe =) but your article is a good base about toasts!
Hi Atrant,
I am beginner for android, this may be a silly question.
My question is, when does the mHandler.post() gets called?
Thanks in advance!
Thaks you :X X.
Muchas gracias!!! Thanks!!!
cool…..it helped a lot
thanx….
Also try setDuration on the Toast object.
Hey Tim,
So setDuration has a funny behavior for Toast objects. It ONLY takes as arguments Toast.LENGTH_LONG and Toast.LENGTH_SHORT – hence you can’t set some custom arbitrary number like 1000 and expect it to stay around for 1000 seconds. Hence the indefinite toast “hack” haha.
– jwei
you can make toasts disappear well by calling Toast. makeText() in UI Thread! read this post -> http://dewr.egloos.com/5464891
whoo hooo! I am trying it out. Nice way to impliment a nice splash screen onResume whoo hoo.
got a 88calls.com android app in the works.
If you are using a Handler (like other comments rightly suggest), then just use the timing facilities of the Handler: