【问题标题】:How to avoid a Toast if there's one Toast already being shown如果已经显示了一个 Toast,如何避免 Toast
【发布时间】:2011-10-19 00:05:03
【问题描述】:

我有几个SeekBaronSeekBarProgressStop(),我想显示一个Toast 消息。

但如果在SeekBar 上我快速执行操作,那么 UI 线程会以某种方式阻塞,Toast 消息会等待直到 UI 线程空闲。

现在我担心的是,如果 Toast 消息已经显示,则要避免新的 Toast 消息。或者他们是我们检查 UI 线程当前空闲的任何条件,然后我将显示 Toast 消息。

我尝试了两种方式,使用runOnUIThread() 并创建新的Handler

【问题讨论】:

    标签: android android-toast


    【解决方案1】:

    我已经尝试了很多方法来做到这一点。起初我尝试使用cancel(),但对我没有效果(另请参阅this answer)。

    setDuration(n) 我也不会去任何地方。通过记录 getDuration() 发现它的值为 0(如果 makeText() 的参数是 Toast.LENGTH_SHORT)或 1(如果 makeText() 的参数是 Toast.LENGTH_LONG)。

    最后我尝试检查吐司的视图isShown()。当然,如果没有显示 toast 则不是,但更重要的是,在这种情况下它会返回一个致命错误。所以我需要尝试捕捉错误。 现在,如果显示 toast,isShown() 返回 true。 利用isShown()我想出了方法:

        /**
         * <strong>public void showAToast (String st)</strong></br>
         * this little method displays a toast on the screen.</br>
         * it checks if a toast is currently visible</br>
         * if so </br>
         * ... it "sets" the new text</br>
         * else</br>
         * ... it "makes" the new text</br>
         * and "shows" either or  
         * @param st the string to be toasted
         */
    
        public void showAToast (String st){ //"Toast toast" is declared in the class
            try{ toast.getView().isShown();     // true if visible
                toast.setText(st);
            } catch (Exception e) {         // invisible if exception
                toast = Toast.makeText(theContext, st, toastDuration);
                }
            toast.show();  //finally display it
        }
    

    【讨论】:

    • 好答案。一句话: isShown() “引发异常”的原因是 toast.getView() 最初返回null。简单地测试 null 而不是使用 try...catch。
    • 您可以考虑直接检查而不是尝试/捕获,因为这是预期的常见情况。
    • 查看我的回答 (stackoverflow.com/a/29573861/2457744),了解如何在不尝试/捕获的情况下进行操作。
    • 当我使用 Toast.LENGTH_SHORT 时它不工作,使用 Toast.LENGTH_LONG 工作正常后。
    • Toast.getView() 在 Android 11+ (stackoverflow.com/questions/62884286/…) 上总是返回 null,所以这个解决方案已经过时了
    【解决方案2】:

    记录您上次展示 toast 的时间,如果它在某个时间间隔内,则重新展示它。

    public class RepeatSafeToast {
    
        private static final int DURATION = 4000;
    
        private static final Map<Object, Long> lastShown = new HashMap<Object, Long>();
    
        private static boolean isRecent(Object obj) {
            Long last = lastShown.get(obj);
            if (last == null) {
                return false;
            }
            long now = System.currentTimeMillis();
            if (last + DURATION < now) {
                return false;
            }
            return true;
        }
    
        public static synchronized void show(Context context, int resId) {
            if (isRecent(resId)) {
                return;
            }
            Toast.makeText(context, resId, Toast.LENGTH_LONG).show();
            lastShown.put(resId, System.currentTimeMillis());
        }
    
        public static synchronized void show(Context context, String msg) {
            if (isRecent(msg)) {
                return;
            }
            Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
            lastShown.put(msg, System.currentTimeMillis());
        }
    }
    

    然后,

    RepeatSafeToast.show(this, "Hello, toast.");
    RepeatSafeToast.show(this, "Hello, toast."); // won't be shown
    RepeatSafeToast.show(this, "Hello, toast."); // won't be shown
    RepeatSafeToast.show(this, "Hello, toast."); // won't be shown
    

    这并不完美,因为 LENGTH_SHORTLENGTH_LONG 的长度未定义,但在实践中效果很好。与其他解决方案相比,它的优势在于您不需要保留 Toast 对象,并且调用语法保持简洁。

    【讨论】:

    • 很好,正是我想要的。效果很好。
    • 也许是个好主意,但没有完美实现。您将对象放入 HashMap 中,但不删除它们。
    • 由于键是要烘烤的字符串,因此映射的大小受要烘烤的字符串数量的限制。仅当您正在烘烤动态字符串(“foo bar”+ i)时,您的观点才有效。如果您需要更好的,请将 HashMap 替换为 LruCache。
    【解决方案3】:

    以下是most popular answer 的替代解决方案,不带try/catch。

    public void showAToast (String message){
            if (mToast != null) {
                mToast.cancel();
            }
            mToast = Toast.makeText(this, message, Toast.LENGTH_SHORT);
            mToast.show();
    }
    

    【讨论】:

    • 最好的,谢谢!
    【解决方案4】:

    适用于停止堆叠,例如点击驱动吐司。基于@Addi 的回答。

    public Toast toast = null;
    //....
    public void favsDisplay(MenuItem item)
    {
        if(toast == null) // first time around
        {
            Context context = getApplicationContext();
            CharSequence text = "Some text...";
            int duration = Toast.LENGTH_SHORT;
            toast = Toast.makeText(context, text, duration);
        }
        try
        {
            if(toast.getView().isShown() == false) // if false not showing anymore, then show it
                toast.show();
        }
        catch (Exception e)
        {}
    }
    

    【讨论】:

      【解决方案5】:

      上述线程的增强功能,仅当与相同的文本消息不可见时才会显示吐司:

       public void showSingleToast(){
              try{
                  if(!toast.getView().isShown()) {    
                      toast.show();
                  }
              } catch (Exception exception) {
                  exception.printStackTrace();       
                  Log.d(TAG,"Toast Exception is "+exception.getLocalizedMessage());
                  toast = Toast.makeText(this.getActivity(),   getContext().getString(R.string.no_search_result_fou`enter code here`nd), Toast.LENGTH_SHORT);
                  toast.show();
              }
      
          }
      

      【讨论】:

        【解决方案6】:

        综合解决方案

        就我而言,如果显示当前的 toast,我需要取消它并显示另一个。

        这是为了解决当用户在服务仍在加载或不可用时请求服务的情况,我需要展示一个 toast(如果请求的服务不同,我可能会有所不同)。否则,toast 会一直按顺序显示,并且需要很长时间才能自动隐藏。

        所以基本上我保存了正在创建的 toast 的实例,下面的代码是如何安全地取消它

        synchronized public void cancel() {
            if(toast == null) {
                Log.d(TAG, "cancel: toast is null (occurs first time only)" );
                return;
            }
            final View view = toast.getView();
            if(view == null){
                Log.d(TAG, "cancel: view is null");
                return;
            }
            if (view.isShown()) {
                toast.cancel();
            }else{
                Log.d(TAG, "cancel: view is already dismissed");
            }
        }
        

        为了使用它,我现在不用担心取消,如下所示:

        if (toastSingleton != null ) {
            toastSingleton.cancel();
            toastSingleton.showToast(messageText);
        }else{
            Log.e(TAG, "setMessageText: toastSingleton is null");
        }
        

        showToast 由您决定如何实现它,因为我需要自定义的 toast 外观。

        【讨论】:

        • 真实逻辑和真实检查空视图,然后再检查是否显示。多次调用显示祝酒词是一种很长很奇怪的体验,尤其是在用户已经退出应用程序的情况下。如您所述,必须取消当前然后调用新的。谢谢。
        【解决方案7】:

        开箱即用的干净解决方案。在你的 Activity 上定义这个:

        private Toast toast;
        
        /**
         * Use this to prevent multiple Toasts from spamming the UI for a long time.
         */
        public void showToast(CharSequence text, int duration)
        {
            if (toast == null)
                toast = Toast.makeText(this, text, duration);
            else
                toast.setText(text);
            toast.show();
        }
        
        public void showToast(int resId, int duration)
        {
            showToast(getResources().getText(resId), duration);
        }
        

        【讨论】:

          【解决方案8】:

          检查是否在屏幕上显示 toast 消息,无论它是否显示。 用于显示 toast 消息创建一个单独的类。并使用此类在检查 toast 消息的可见性后显示 toast 消息的方法。使用这段代码:

          public class AppToast {
          
          private static Toast toast;
          
          public static void showToast(Context context, String message) {
              try {
                  if (!toast.getView().isShown()) {
                      toast=Toast.makeText(context, message, Toast.LENGTH_SHORT);
                      toast.show();
                  }
              } catch (Exception ex) {
                  toast=Toast.makeText(context,message,Toast.LENGTH_SHORT);
                  toast.show();
              }
          }
          
          }
          

          我希望这个解决方案对你有所帮助。

          谢谢

          【讨论】:

            【解决方案9】:

            添加了 2 秒后移除吐司的计时器。

            private Toast toast;
            
            public void showToast(String text){
                    try {
                        toast.getView().isShown();
                        toast.setText(text);
                    }catch (Exception e){
                        toast = Toast.makeText(mContext, text, Toast.LENGTH_SHORT);
                    }
                    if(toast.getView().isShown()){
                        new Timer().schedule(new TimerTask() {
                            @Override
                            public void run() {
                                toast.cancel();
                            }
                        }, 2000);
                    }else{
                        toast.show();
                    }
                }
            
            showToast("Please wait");
            

            【讨论】:

              【解决方案10】:

              我的解决办法是:

              public class Utils {
                  public static Toast showToast(Context context, Toast toast, String str) {
                      if (toast != null)
                          toast.cancel();
                      Toast t = Toast.makeText(context, str, Toast.LENGTH_SHORT);
                      t.show();
                      return t;
                  }
              }
              

              并且调用者应该有这个方法参数的 Toast 成员,或者

              class EasyToast {
                  Toast toast;
                  Context context;
              
                  public EasyToast(Context context) {
                      this.context = context;
                  }
              
                  public Toast show(String str) {
                      if (toast != null)
                          toast.cancel();
                      Toast t = Toast.makeText(context, str, Toast.LENGTH_SHORT);
                      t.show();
                      return t;
                  }
              
              }
              

              有一个这样的辅助类。

              【讨论】:

              • 我找到了同样的解决方案。如果 isShown() 没有按预期工作,那么就不要使用它:) 如果它不为空,则取消() toast。
              猜你喜欢
              • 1970-01-01
              • 2015-06-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-12-01
              • 2011-03-30
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多