3

Assume that you have a Button that whenever you click on it, it displays a Toast with the message "Hello". If you decide to click on that Button 20 times repeatedly, the Toasts will be displayed asynchronously, waiting each one its turn. However, this is not what I really want.

What I want is the following: Whenever I press the Button, I want it to cancel the previous displayed Toast and display the actual one. So that when I close the app, no Toasts will be displayed if ever the user decides to mess with the app by clicking on the Button 100 times within a very small period.

Alex
  • 1,639
  • 3
  • 18
  • 33

2 Answers2

6

You'll need to declare your Toast at a class level, and then call toast.cancel() before constructing a new Toast object and showing it.

public class XYZ extends Activity {

    Toast mToast;

    public void onCreate(Bundle b) {
    .....
    button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if(mToast != null) 
                    mToast.cancel();
                mToast = Toast.makeText.....;
            }

        });
    }

}
Raghav Sood
  • 81,899
  • 22
  • 187
  • 195
  • Thank you this is what i was just thinking of right now!! haha thanks a lot! :) – Alex Mar 28 '13 at 23:35
  • The `Toast`s are no longer displayed asynchronously, thank you! However, the last `Toast` is always being displayed. By the way, I added `if(t!=null)mToast.cancel();` in `onDestroy()`; the only problem remaining is the last Toast. Any idea? – Alex Mar 28 '13 at 23:46
  • @JonathanHugh Yep. That's because its still in the queue when the activity shuts. You should add `if(mToast != null) mToast.cancel();` to `onPause()` instead, as there is no guarantee onDestroy will be called. – Raghav Sood Mar 28 '13 at 23:47
  • Awesome. I'll change that. But, my problem is not with the `onDestroy` method, what i was saying is that whenever i click on the `Button` many times repeatedly, the last `Toast` is being displayed after a certain amount of time. I want that last `Toast `to appear immediately after clicking the last Press, not after waiting few seconds. If you didn't get what I mean it's ok.. i'll go over it... – Alex Mar 28 '13 at 23:51
  • @JonathanHugh Ah okay. That's probably due to a delay in clearing up the toast queue with all the cancelled toasts from previous clicks. I don't think there's much you can do about it. – Raghav Sood Mar 28 '13 at 23:53
  • Do not use Toast.cancel(), use Toast.setText("") instead. – VipulKumar Dec 30 '14 at 07:24
0

Here' another solution. If all you want is to prevent multiple toasts from being displayed for fast clicks then a combination of AlarmManager and a PendingIntent should work too. Now bear in mind, I haven't tested this and haven't checked if it compiles.

AlarmManager mAlarm;
PendingIntent mPendingIntent;
//toast delay for a second
int toastDelay = 1000;

@Override
public void onCreate (Bundle savedInstanceState) {
   Intent i = new Intent(context, MySimpleBroadcastReceiver.class);

   //optionally set an action
   i.setAction("show:toast");

   mPendingIntent = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);

   mAlarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}

public void onClick(View v) {
   //set the alarm to trigger 1 second from current time
   mAlarm.set(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis() + toastDelay), mPendingIntent);
}

@Override
protected void onDestroy () {
   if (mAlarm != null) {
      mAlarm.cancel(mPendingIntent);
   }
   mAlarm = null;
   mPendingIntent = null;
}

Create the broadcast receiver and remember to add it to your AndroidManifest.xml:

public class MySimpleBroadcastReceiver extends BroadcastReceiver {
   @Override
   public void onReceive (Context context, Intent intent) {
      //optionally check the action that triggered the broadcast..useful if you want to use this broadcast for other actions
      if (intent.getAction().equals("show:toast")) {
         Toast.makeText(context, "Hello", Toast.LENGTH_SHORT).show();
      }
   }
}

You can read about PendingIntent.FLAG_CANCEL_CURRENT.

praneetloke
  • 1,953
  • 1
  • 14
  • 15
  • 1
    Uh, why would you go to all the trouble of creating a BroadcastReceiver, setting an alarm and using pending intents over toast.cancel()? Does this method offer any distinct advantage worth all the overhead of all these additional objects and code to maintain? – Raghav Sood Mar 29 '13 at 00:05
  • I think @RaghavSood is right. No need to do all this for a chick called `Toast`. Thank you anyway, appreciate your intention to help :) – Alex Mar 29 '13 at 00:18
  • I do not know if there's a distinct advantage over simply doing a toast.cancel() as I have not run either of the codes posted on this page but I do use PendintIntents to manipulate actions that occur close to each other to eliminate duplicates. Hence I thought I'd show its usefulness by using it here. – praneetloke Mar 29 '13 at 00:22
  • Also, see alarm.set info here http://developer.android.com/reference/android/app/AlarmManager.html#set(int, long, android.app.PendingIntent)...Basically, it will cancel out previously set alarms automatically for the same inents which means if your user taps on the button 100 times, only the 100th tap will trigger the alarm which will send a broadcast to the receiver and show a toast. – praneetloke Mar 29 '13 at 00:29