Android应用退出时取消Toast显示,以及在Toast正在显示时取消其显示。

10

我在这里阅读了这种问题的相关信息,但是答案似乎没有起作用。

当用户点击按钮时,我会展示一个Toast。当用户连续点击该按钮时,即使用户退出活动,Toast仍然会一遍又一遍地显示。

Toast的长度很短,由于文本过长,Toast的长度无法更改。

目前为止,我尝试过以下方法:

    Toast toast;
    toast=Toast.makeText(getApplicationContext(),"text",Toast.LENGTH_SHORT);
    if(toast.getView().isShown()==false){
         toast.show();
    }

这没有起作用。

我尝试过:

    if(toast.getView().isShown()==true){            
        toast.cancel();
    }

onStop()方法中,由于某种原因,cancel方法从未起作用。

如果我将.cancel()放在显示应用程序之前......那么还会有另一个空指针检查。但是即使这样做也没有用。我可以显示对话框而不是Toast,但那不是解决办法。

有没有办法检查是否正在显示Toast?

参考:


使用onPause()代替onStop()... - Triode
我对这个概念感到困惑。 onPause 在停止之前被调用,但当活动变化时它们也会被调用。它们有什么区别?它们各自用于什么? 我使用 onStop 停止所有异步线程和对话框。 - Ciff
点击一次后,使按钮不可见。 - Raghunandan
有没有办法检查 Toast 是否正在显示? - Ciff
4个回答

17
关键在于跟踪上次显示的最后一个Toast,并取消它。
我所做的是创建了一个Toast包装器,其中包含对上一个显示的Toast的静态引用。
当我需要显示新的Toast时,我首先取消静态引用,然后显示新的Toast(并将其保存在静态中)。
这是我制作的Boast包装器的完整代码 - 它模仿了足够多的Toast方法供我使用。默认情况下,Boast将取消前一个,因此您不会积累等待显示的Toast队列。
这段代码可以在我的Github Gist中找到: 如果您只想知道如何在退出应用程序时取消通知,则可以在其中找到许多帮助。如果您有改进或建议,请随时分支并联系我们。这是一个非常古老的答案,但代码已经在一些应用程序中稳定运行了一段时间。

顺便说一句- 在大多数使用情况下,这应该是 Toast 的直接替代品。


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();
    }

}

谢谢。但是取消 Toast 的方法肯定还有其他替代方案。如果我们能知道 Toast 是否正在显示... - Ciff
@Ciff 查看Android源代码,您可以尝试调用 Toast.getView() - 但仍然需要对该对象的引用,即您需要跟踪上一次显示的Toast。在这种情况下查看源代码可能会帮助您很多,因为它是相当简单的代码 - 它还显示了许多Toast功能由系统本身处理,无法被我们访问。 - Richard Le Mesurier
继承Toast会不会更短、更好看呢? - acrespo
也许它会吗?结果可能因人而异。 - Richard Le Mesurier
1
无法工作,我在屏幕上有三个提示框,一个接一个地显示。然而,它会取消前一个提示框,但感觉好像所有提示框都已经显示了。 - Geek
显示剩余3条评论

5
不要取消弹出文本提示框,而是更改显示的文本内容。例如:
        Toast t;

        t = Toast.makeText(this, "hi", 3000);
        t.show();

当您需要不同的Toast时,请使用以下代码:
        t.setText("bye");
        t.show();

如果您想要关闭提示,只需调用t.cancel()


有没有办法检查Toast是否正在显示? - Ciff
@Ciff 看这个.. https://dev59.com/N1XTa4cB1Zd3GeqPzDDn#5295800 - stinepike

1
尝试保留上一个提示的时间戳,并在超时时间内不允许出现任何新提示。类似于:
private static final long TOAST_TIMEOUT_MS = 2000; // tweak this constant

private static long lastToastTime = 0;

public void onButtonClicked() {
  long now = System.currentTimeMillis();
  if (lastToastTime + TOAST_TIMEOUT_MS < now) {
    Toast.makeText(...).show();
    lastToastTime = now;
  }
}

我不会担心当用户退出应用程序后,单个提示信息仍然存在一两秒的情况——这是一种相当标准的行为。


有没有办法检查一个Toast是否正在显示? - Ciff
这是我唯一有效的方法。这就是正确的方式! - Felix A Marrero Pentón

1
您可以通过调用Toast对象上的cancel()方法来取消单个Toast。据我所知,没有办法取消所有未完成的Toast。

有没有办法检查 Toast 是否正在显示? - Ciff
这个答案与CommonsWare在此重复问题的答案完全相同:https://dev59.com/wXE85IYBdhLWcg3wejfn - stevehs17

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接