【问题标题】:How to prevent Multiple Toast Overlaps如何防止多个 Toast 重叠
【发布时间】:2012-10-07 00:20:39
【问题描述】:

我一直在使用常见的“myToast”,在发布新的 toast 之前我使用“myToast.cancel()”。对于 Android v2.3 及更早版本,这很好用。当需要发送新的 toast 时,旧的一个,如果仍然在屏幕上,被取消(并立即消失)以替换为新的 toast。如果用户多次按下需要警报(和其他条件)的键,这可以避免堆叠一堆 toast。我的实际情况是按错键出现一个toast,没有按Clear键出现另一个。

对于 Android 4.0 和 4.1,在下一个 toast 之前发出 myToast.cancel() 会杀死当前和下一个 toast。当前的cancel() API 确实表明它取消了当前和下一个吐司(这似乎相当愚蠢)。为什么要取消你想举的祝酒词?

有什么想法可以让取消在 Android 版本之间保持一致(以及它在 v2.3 和更早版本中的工作方式)?

我会尝试一些不雅的双 toast 系统,它可以跟踪正在使用的 toast,但是在 4.x 中解决这个不良行为似乎很难在较旧的 Android 版本中完美且合乎逻辑地工作。


好的,我解决了,但它不像我希望的那样干净。我实现了一种双吐司方法,它在两个吐司之间交替。首先我们为OnCreate之前的活动定义toast:

Toast toast0;
Toast toast1;
private static boolean lastToast0 = true;

在 OnCreate 中:

toast0 = new Toast(getApplicationContext());
toast0.cancel();
toast1 = new Toast(getApplicationContext());
toast1.cancel();

最后,当我需要显示 toast 并同时取消之前的 toast 时,我会使用类似于:

if (lastToast0) {
    toast0.cancel();
    toast1.setDuration(Toast.LENGTH_LONG);
    toast1.setText("new message");
    toast1.show();
    lastToast0 = false;
} else {
    toast1.cancel();
    toast0.setDuration(Toast.LENGTH_LONG);
    toast0.setText("new message");
    toast0.show();
    lastToast0 = true;
}

如果您只需要取消现有的 toast(在超时之前),请使用:

toast0.cancel();
toast1.cancel();

在 Nexus 7 (4.1)、Emulator 4.0 和多款搭载 Android 2.2、2.3 的设备上测试。

【问题讨论】:

  • 如何取消旧的吐司?在制作新的之前还是之后?
  • 你能把你的代码贴在你正在烤的地方吗?
  • 我在新的之前取消了它 - 这就是为什么 Android 4.x 隐藏了新的如此奇怪(但 toast cancel 的 API 解释了会发生这种情况)。我在我创建的有效解决方案中进行了编辑。只是看起来不太好看。
  • 您的解决方案确实不干净,但它似乎工作得很好。并且下面的@nandeesh 解决方案在我的 Android 11 中不起作用(在 logcat 中出现Toast already killed 警告后活动崩溃)。

标签: android toast


【解决方案1】:

而不是调用cancel()。尝试重置文本并致电show()。这应该自行取消最后一个 toast

myToast.setText("wrong key")
myToast.show();

如果您继续使用相同的myToast 而不是每次都创建一个,我猜它们不会叠加。

【讨论】:

  • 完美!感谢分享:)
  • 这有时会在logcat 中出现Toast already killed 警告后强制我的 Android 11 中的活动崩溃。
【解决方案2】:

nandeesh 的解决方案不适合您吗? 他的解决方案比使用两种不同的吐司更清洁。

例如,(扩展他/她的答案)在 onCreate 之前,我们会声明 toast:

private Toast myToast;

在 onCreate 中我们必须使用 makeToast 来初始化它(否则我们会得到一个错误):

myToast = Toast.makeText(getApplicationContext(), null, Toast.LENGTH_SHORT);

每当我们想要显示祝酒词时,我们只需调用:

myToast.setText("some text");
myToast.show();

这将正确地替换以前的吐司。

【讨论】:

  • 我不确定你在哪里读到 Nandeesh 建议使用两个祝酒词,他明确表示 If you keep using the same myToast instead of creating one everytime i guess they wont stack up. 在这一点上,我认为你的答案和他的答案没有区别。另外,我建议您写下您的答案,不要将您的答案与其他人的答案进行比较。这对我来说听起来很粗鲁,尤其是当你说他们的答案是错误的时。
  • 我在哪里说南迪斯用了两个吐司?此外,我的回答只是在他的基础上进行扩展并举一个更长的例子。
  • 对不起,这仍然让我感到困惑Did nandeesh's solution not work for you? His solution would be cleaner than using two different toasts. 我不确定你为什么要指出他的答案然后发布类似的答案,我的意思是他的答案中缺少的部分并没有它“不工作”IMO。
  • 这应该回答应该是评论而不是
  • 这有时会在logcat 中出现Toast already killed 警告后强制我的 Android 11 中的活动崩溃。
【解决方案3】:

这是我从另一个类似问题中复制的答案:

Boast 类完全满足您的需求。


诀窍是跟踪显示的最后一个Toast,然后取消那个。

我所做的是创建一个 Toast 包装器,其中包含对显示的最后一个 Toast 的静态引用。

当我需要显示一个新的时,我首先取消静态引用,然后再显示新的(并将其保存在静态中)。

这是我制作的 Boast 包装器的完整代码 - 它模仿了足够多的 Toast 方法供我使用。默认情况下,Boast 将取消前一个,因此您不会建立等待显示的 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();
    }

}

【讨论】:

  • 我喜欢你的解决方案,它在 4.x 上运行良好,但你知道为什么它不能在 2.x 上运行吗? (我没试过3.x)
  • 抱歉不知道。这是生产代码,我想我已经测试了它的向后兼容性。如果以后发现什么,会重新发布。
【解决方案4】:

cancel() 恐怕什么也没做。

我建议使用 Crouton https://github.com/keyboardsurfer/Crouton

【讨论】:

  • 在新的 toast 之前使用 toast.cancel() 部分有效 - 如果存在的话,现有的 toast 会消失。改变的是在 Android 4.x(可能是 3.x)中,它还隐藏了我想用第一个 toast 替换的下一个 toast!
【解决方案5】:

将 java 类设为 ShowToast.java,如下所示

    public class ShowToast {

        private static Toast toast;

        public static void show(Context mcontext, String text) {
            if (toast != null) 
               toast.cancel();
            toast = Toast.makeText(mcontext, text, Toast.LENGTH_SHORT);
            toast.show();
        }
    }

然后称它为

    ShowToast.show(getApplicationContext(),"YOUR_TOAST_TEXT");

【讨论】:

    【解决方案6】:

    我的解决方案适用于 4.* 和 2.3 Android 版本

    static Toast toast;
    .....
    
    if (toast != null)
        toast.cancel();
    
    boolean condition = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
    if ((toast == null && condition) || !condition)
        toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
    if ((toast != null && condition))
        toast.setText(text);
    toast.show();
    

    【讨论】:

      【解决方案7】:

      创建一个 Toast 对象:

      Toast toastobject=null;
      

      现在使用下面的代码来显示吐司。这对我有用

          int index = clickCounter-1;
      
      
          if(toastobject!= null)
                  {
                      toastobject.cancel();
                  }
                  toastobject = Toast.makeText(this,"Toast Text" , Toast.LENGTH_SHORT);
                  listItems.remove(index);
                  toastobject.show();
      

      【讨论】:

        【解决方案8】:

        创建新函数并调用它。

        ImageButton ABtn = (ImageButton) findViewById(R.id.Btn);
        ABtn.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v)
        {       
        SETToast("mytext");
        }
        });
        
            private Toast toast = null;
        
        public void SETToast( String text)
        {
          if(toast==null)
          {
             toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT); 
             toast.show();
             final Handler handler = new Handler(); 
             handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    toast=null;
                }
             }, 2000);
          }
          else
          {
              toast.setText(text);
          }   
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-03
          • 2020-05-09
          相关资源
          最近更新 更多