Skip to content

Indefinite Toast Hack

February 19, 2010

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

14 Comments leave one →
  1. February 20, 2010 10:34 pm

    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.

    • Donna Michee permalink
      July 16, 2012 7:27 pm

      It’s probably one of those insidious things that works on some devices but causes problems on others. Gotta love Android.

  2. atrant permalink
    April 18, 2010 11:06 pm

    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!

    • ssk permalink
      February 6, 2011 1:20 am

      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!

  3. vietbq permalink
    August 17, 2010 1:53 am

    Thaks you :X X.

  4. Joshua03 permalink
    October 8, 2010 2:36 am

    Muchas gracias!!! Thanks!!!

  5. garima permalink
    November 25, 2010 9:53 pm

    cool…..it helped a lot
    thanx….

  6. January 3, 2011 9:48 am

    Also try setDuration on the Toast object.

    • January 5, 2011 1:51 pm

      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

  7. January 9, 2011 8:42 pm

    you can make toasts disappear well by calling Toast. makeText() in UI Thread! read this post -> http://dewr.egloos.com/5464891

  8. March 4, 2011 2:29 am

    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.

  9. May 27, 2011 1:35 am

    If you are using a Handler (like other comments rightly suggest), then just use the timing facilities of the Handler:

        protected void toast(String s) {
    	final Toast message = Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT);
    	message.show();
    	final long duration = s.length() * 100;
    	for (int i = 1000; i < duration; i += 1000) {
    	    handler.postDelayed(new Runnable() {
    		    public void run() {
    			message.show();
    		    }
    		}, i);
    	}
        }
    

Trackbacks

  1. Indefinite Toast Hack « Think Android « Blog
  2. Using separate threads for looping emphasis on Android | Mobile Techq

Leave a comment