36

In my app, I construct a calendar widget for my activity, when I scroll it to previous or next month, I let it make a toast and show it.

The question is, the toast need time to show, when I scroll it fast enough, for example, I scrolled to "2012/05" and "2012/06" and scroll to "2012/07" without pause, I have to wait the Toast of "2012/05", "2012/06","2012/07" to show one by one slowly.

Seems like Android has an invisible queue to manage toasts

how can I clean it and only show the last toast? Can I show a specific Toast immediately without waiting?

I searched the "android.widget.Toast.java" and find a method cancel(), but unfortunately it does not work as follows.

if (t != null) {
    t.cancel();
}
t = Toast.makeText(this.mContext, mHelper.getYear() + "年"
                + (mHelper.getMonth() + 1) + "月", Toast.LENGTH_SHORT);
t.show();
Neeraj Sewani
  • 3,952
  • 6
  • 38
  • 55
topxebec
  • 1,417
  • 3
  • 15
  • 29
  • 2
    I've been trying to figure it out but honestly I have no idea why it doesn't work. your code should work if cancel() did what it says it does. maybe you'll have to use something else instead of toasts. – Joe Apr 09 '12 at 08:31
  • @topxebec your code should work. It forms the basis of my `Boast` class reference in answer below http://stackoverflow.com/a/16103514/383414 – Richard Le Mesurier Apr 19 '13 at 11:27

12 Answers12

30

You just need to declare a "Toast" var like this:

Toast toastMessage;

Then in your function, do it like this:

if (toastMessage!= null) {
    toastMessage.cancel();
}
toastMessage= Toast.makeText(context, "The message you want to display", duration);
toastMessage.show();
Karthik Kompelli
  • 2,104
  • 1
  • 19
  • 22
JCarangoH
  • 301
  • 3
  • 7
24

Here is my answer copied from another similar question here:

The Boast class accomplishes exactly what you need. Most recent code can be found on GitHub here:


The trick is to keep track of the last Toast that was shown, and to cancel that one.

What I have done is to create a Toast wrapper, that contains a static reference to the last Toast displayed.

When I need to show a new one, I first cancel the static reference, before showing the new one (and saving it in the static).

Here's full code of the Boast wrapper I made - it mimics enough of the Toast methods for me to use it. By default the Boast will cancel the previous one, so you don't build up a queue of Toasts waiting to be displayed.

If you just want to know how to cancel the notifications when exiting your app, you will find lots of help in there.


package mobi.glowworm.lib.ui.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.support.annotation.Nullable;
import android.widget.Toast;

import java.lang.ref.WeakReference;

/**
 * {@link Toast} decorator allowing for easy cancellation of notifications. Use this class if you
 * want subsequent Toast notifications to overwrite current ones. </p>
 * <p/>
 * By default, a current {@link Boast} notification will be cancelled by a subsequent notification.
 * This default behaviour can be changed by calling certain methods like {@link #show(boolean)}.
 */
public class Boast {
    /**
     * Keeps track of certain Boast notifications that may need to be cancelled. This functionality
     * is only offered by some of the methods in this class.
     * <p>
     * Uses a {@link WeakReference} to avoid leaking the activity context used to show the original {@link Toast}.
     */
    @Nullable
    private volatile static WeakReference<Boast> weakBoast = null;

    @Nullable
    private static Boast getGlobalBoast() {
        if (weakBoast == null) {
            return null;
        }

        return weakBoast.get();
    }

    private static void setGlobalBoast(@Nullable Boast globalBoast) {
        Boast.weakBoast = new WeakReference<>(globalBoast);
    }


    // ////////////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * Internal reference to the {@link Toast} object that will be displayed.
     */
    private Toast internalToast;

    // ////////////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * Private constructor creates a new {@link Boast} from a given {@link Toast}.
     *
     * @throws NullPointerException if the parameter is <code>null</code>.
     */
    private Boast(Toast toast) {
        // null check
        if (toast == null) {
            throw new NullPointerException("Boast.Boast(Toast) requires a non-null parameter.");
        }

        internalToast = toast;
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * Make a standard {@link Boast} that just contains a text view.
     *
     * @param context  The context to use. Usually your {@link android.app.Application} or
     *                 {@link android.app.Activity} object.
     * @param text     The text to show. Can be formatted text.
     * @param duration How long to display the message. Either {@link Toast#LENGTH_SHORT} or
     *                 {@link Toast#LENGTH_LONG}
     */
    @SuppressLint("ShowToast")
    public static Boast makeText(Context context, CharSequence text, int duration) {
        return new Boast(Toast.makeText(context, text, duration));
    }

    /**
     * Make a standard {@link Boast} that just contains a text view with the text from a resource.
     *
     * @param context  The context to use. Usually your {@link android.app.Application} or
     *                 {@link android.app.Activity} object.
     * @param resId    The resource id of the string resource to use. Can be formatted text.
     * @param duration How long to display the message. Either {@link Toast#LENGTH_SHORT} or
     *                 {@link Toast#LENGTH_LONG}
     * @throws Resources.NotFoundException if the resource can't be found.
     */
    @SuppressLint("ShowToast")
    public static Boast makeText(Context context, int resId, int duration)
            throws Resources.NotFoundException {
        return new Boast(Toast.makeText(context, resId, duration));
    }

    /**
     * Make a standard {@link Boast} that just contains a text view. Duration defaults to
     * {@link Toast#LENGTH_SHORT}.
     *
     * @param context The context to use. Usually your {@link android.app.Application} or
     *                {@link android.app.Activity} object.
     * @param text    The text to show. Can be formatted text.
     */
    @SuppressLint("ShowToast")
    public static Boast makeText(Context context, CharSequence text) {
        return new Boast(Toast.makeText(context, text, Toast.LENGTH_SHORT));
    }

    /**
     * Make a standard {@link Boast} that just contains a text view with the text from a resource.
     * Duration defaults to {@link Toast#LENGTH_SHORT}.
     *
     * @param context The context to use. Usually your {@link android.app.Application} or
     *                {@link android.app.Activity} object.
     * @param resId   The resource id of the string resource to use. Can be formatted text.
     * @throws Resources.NotFoundException if the resource can't be found.
     */
    @SuppressLint("ShowToast")
    public static Boast makeText(Context context, int resId) throws Resources.NotFoundException {
        return new Boast(Toast.makeText(context, resId, Toast.LENGTH_SHORT));
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * Show a standard {@link Boast} that just contains a text view.
     *
     * @param context  The context to use. Usually your {@link android.app.Application} or
     *                 {@link android.app.Activity} object.
     * @param text     The text to show. Can be formatted text.
     * @param duration How long to display the message. Either {@link Toast#LENGTH_SHORT} or
     *                 {@link Toast#LENGTH_LONG}
     */
    public static void showText(Context context, CharSequence text, int duration) {
        Boast.makeText(context, text, duration).show();
    }

    /**
     * Show a standard {@link Boast} that just contains a text view with the text from a resource.
     *
     * @param context  The context to use. Usually your {@link android.app.Application} or
     *                 {@link android.app.Activity} object.
     * @param resId    The resource id of the string resource to use. Can be formatted text.
     * @param duration How long to display the message. Either {@link Toast#LENGTH_SHORT} or
     *                 {@link Toast#LENGTH_LONG}
     * @throws Resources.NotFoundException if the resource can't be found.
     */
    public static void showText(Context context, int resId, int duration)
            throws Resources.NotFoundException {
        Boast.makeText(context, resId, duration).show();
    }

    /**
     * Show a standard {@link Boast} that just contains a text view. Duration defaults to
     * {@link Toast#LENGTH_SHORT}.
     *
     * @param context The context to use. Usually your {@link android.app.Application} or
     *                {@link android.app.Activity} object.
     * @param text    The text to show. Can be formatted text.
     */
    public static void showText(Context context, CharSequence text) {
        Boast.makeText(context, text, Toast.LENGTH_SHORT).show();
    }

    /**
     * Show a standard {@link Boast} that just contains a text view with the text from a resource.
     * Duration defaults to {@link Toast#LENGTH_SHORT}.
     *
     * @param context The context to use. Usually your {@link android.app.Application} or
     *                {@link android.app.Activity} object.
     * @param resId   The resource id of the string resource to use. Can be formatted text.
     * @throws Resources.NotFoundException if the resource can't be found.
     */
    public static void showText(Context context, int resId) throws Resources.NotFoundException {
        Boast.makeText(context, resId, Toast.LENGTH_SHORT).show();
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * Close the view if it's showing, or don't show it if it isn't showing yet. You do not normally
     * have to call this. Normally view will disappear on its own after the appropriate duration.
     */
    public void cancel() {
        internalToast.cancel();
    }

    /**
     * Show the view for the specified duration. By default, this method cancels any current
     * notification to immediately display the new one. For conventional {@link Toast#show()}
     * queueing behaviour, use method {@link #show(boolean)}.
     *
     * @see #show(boolean)
     */
    public void show() {
        show(true);
    }

    /**
     * Show the view for the specified duration. This method can be used to cancel the current
     * notification, or to queue up notifications.
     *
     * @param cancelCurrent <code>true</code> to cancel any current notification and replace it with this new
     *                      one
     * @see #show()
     */
    public void show(boolean cancelCurrent) {
        // cancel current
        if (cancelCurrent) {
            final Boast cachedGlobalBoast = getGlobalBoast();
            if ((cachedGlobalBoast != null)) {
                cachedGlobalBoast.cancel();
            }
        }

        // save an instance of this current notification
        setGlobalBoast(this);

        internalToast.show();
    }

}
Community
  • 1
  • 1
Richard Le Mesurier
  • 29,432
  • 22
  • 140
  • 255
  • 1
    does not seem to work in gingerbread BTW, there the old toast stays visible and new toast comes after it – The Nail Jun 12 '13 at 20:56
  • @thenail Thx for feedback. Which device if you will? Was working on our Samsung 2.3 device but can't remember what model. And worked on HTC Desire 2.2, Galaxy Nexus 4.1. Feedback appreciated. – Richard Le Mesurier Jun 12 '13 at 21:57
  • 1
    Awersome! Just a fix that works for me, I changed the private constructor to public and then I used your class like: mBoast = new Boast(new Toast(this)); mBoast.makeText(...); Thanks for share your Boast class =) – Daniel S. Jun 16 '14 at 14:30
  • 1
    @Richard Le Mesurier It will leak memory due to static reference of globalBoast. – Min2 Jun 12 '16 at 10:24
  • 1
    Thanks, this fixes the issue without having to clutter activities with toast references. It would be nice to put this on github to enable possible further improvements – Mike76 Aug 16 '16 at 20:22
  • @Mike76 it has been up for a while, here is the link to [Boast.java](https://gist.github.com/mobiRic/9786993). Pls feel free to fork or fix, it has worked well for me in production for years, but all code can be improved. – Richard Le Mesurier Aug 16 '16 at 20:38
  • 1
    @Magicode we had a lot of laughs in the office that day to be sure! ~very tongue in cheek~ – Richard Le Mesurier Aug 16 '16 at 20:45
  • 1
    @Min2 I finally got round to investigating your comment properly - you are 100% right. Using LeakCanary I found that `Toast` does not actually leak the context (which surprised me), and `Boast` of course did. Thanks for your comment which has bugged me for a while - code has been updated to use `WeakReference` which seems to fix the leak. If you have the time, I'd be interested in your feedback as yours was a very constructive comment. – Richard Le Mesurier Mar 17 '17 at 07:51
19

You need to call method on correct object.

toastObject.cancel()
Mohammed Azharuddin Shaikh
  • 41,633
  • 14
  • 96
  • 115
7

Here is the Code.

final Toast toastobject = Toast.makeText(context, "This message will disappear when toast.close(); is called", Toast.LENGTH_SHORT);

Now you can use the Object of toastobject. Its Reference

toastobject.cancel();

You can use it in Thread or whenever you would like to Close the Toast.

Bhavin
  • 6,020
  • 4
  • 24
  • 26
6

You can reuse a toast, this will make it display immediately.

myToast.setText(toastMsg);
myToast.show();
user3533716
  • 491
  • 7
  • 14
3

There are many ways by which we can cancel previous Toast when we want to show another Toast. below I have written a simplest an easy way to implement it. First of all, we have to create a variable which can be accessed in the whole class.

private Toast toast;

After creating the variable which can be accessed by whole class we have to create a method in our class which displays the toast message and checks if the previous toast is displaying then cancel it.

   public void showToast(String message) {
    if (toast != null) {
        toast.cancel();
    }
    toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT);
    toast.show();
}

you can change toast message by runtime calling above method.

showToast("message 1");

//after some time

showToast("message 2");

hope it helps.

Gaurang Goda
  • 3,394
  • 4
  • 20
  • 29
1

Toast has a method to hide current toast message

public void cancel() {
    mTN.hide();
}

Try calling t.cancel() when it is necessary.

JonA
  • 605
  • 6
  • 6
  • 1
    @JonA - Yes, exactly. @topxebec - The trick is to retain that instance of the original toast - `mTN`. That is what catches a lot of people out. You cannot just create a new `Toast` and try to cancel that one - you need to cancel the original one. – Richard Le Mesurier Jul 03 '13 at 13:24
1

You can create static method and use it to show a toast:

public static Toast toast = null;
public static showToast(Context context,String msg){
if(toast!=null)             //this will cancel the toast on the screen if one exists
   toast.cancel();
toast = Toast.makeText(context,msg);
toast.show();
}
tun
  • 39
  • 4
1

Simple. Simply call the method .cancel() on the toast once you want to create another toast.

Start by defining a Toast variable at the top of your class like this

private Toast mToast;

Later, When you want to create a new Toast(and have the old one disappear), do this.

if(mToast != null) {
  mToast.cancel();  //if a toast exists it deletes it, allowing you to create a new one
}


mToast = Toast.makeText(this, "This will show up now!", Toast.LENGTH_LONG);
mToast.show(); //creates the new toast. 
Sreehari R
  • 919
  • 4
  • 11
  • 21
0
public static Toast  sToast=null;

// create Toast object;

public void showToast(String msg)

    {

    //here is checking whether toast object is null or not;if not null gonna cancel the toast that is showing in phone window and make it null;  

    if(sToast!=null)
    {

      sToast.cancel;

    sToast=null;
    }

    //if toast object is null,gonna create new instance and make it shown on phone window.

    if(sToast==null)
    {

        sToast=Toast.makeText(currentActivity.this,msg,Duration);

        sToast.setGravity();

        sToast.show();

    }

}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
0

Belatedly: The reason your code doesn't work is that Toast.makeText() does not return a reference to the Toast it is creating. It is just a helper method designed to allow Toast to be created quickly and easily, but doesn't allow for reference or cancellation. To cancel, you would have to do:

t=Toast(requireContext())
t.setText(YOUR TEXT)
t.setDuration(1000)
t.show()

This way t would be assigned a reference when the constructor was called, which would allow for cancellation later.

Viktor Jovanovski
  • 1,513
  • 10
  • 26
Wallaceness
  • 1
  • 1
  • 6
-1

You can use one shoot technique. Oke let's start defining:

private Toast mToast;
private showOnce=false;

Later when you wanna show toast once:

if(showOnce==false){
  mToast=Toast.makeText(this, "Once!", Toast.LENGTH_LONG);
  mToast.show();
  showOnce=true;
}
Jetwiz
  • 642
  • 7
  • 14