I'm trying to understand the functionality, and in particular, one particular reason why we use removeCallbacks()
in conjunction with postDelayed()
by going through the Fullscreen Activity template provided in Android Studio. In the fullscreen activity template, when the screen is touched it will show/hide the status bar and navigation/system bar after a certain number of milliseconds, and in this template's case 3000 milliseconds.
private void hide() {
// Hide UI first
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
mControlsView.setVisibility(View.GONE);
mVisible = false;
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable); // <------ Comment/uncomment
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}
@SuppressLint("InlinedApi")
private void show() {
// Show the system bar
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mVisible = true;
// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable); // <------ Comment/uncomment
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
}
/**
* Schedules a call to hide() in [delay] milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide(int delayMillis) {
mHideHandler.removeCallbacks(mHideRunnable); // <------ Comment/uncomment
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}
I understand that removeCallbacks()
is used to remove the pending messages/runnables from the message queue but is there a particular reason why we would use it other than if a condition is met and we no longer want the pending messages/runnables to be executed?
I ask this because in regards to the Fullscreen Activity template I'm a bit confused here as it seems that if i don't call mHideHandler.removeCallbacks(Runnable)
when using postDelayed()
then it'll allow the user to spam the hide/show methods. With the spamming it looks like the transition animation is interrupted and that the animation may even get stuck during the spam because it was stopped at a certain point during the transition. However, if I do call mHideHandler.removeCallbacks(Runnable)
right before postDelayed()
then it'll prevent the users from spamming the hide/show methods, which is good.
I guess in short my question is how does mHideHandler.removeCallbacks(Runnable)
prevent the spamming of methods being called when used with postDelayed()
? Question is similar to this question but am hoping to get an explanation on why this occurs.
Here are the differences in .gif form. Using removeCallbacks() is the intended behaviour while commenting out removeCallbacks() leads to unwanted "abuse" behaviour:
EDIT: Added in .gifs and added comments to the removeCallbacks() in the code to help identify which part of the code i'm talking about.
Each time you perform a click you are posting an event to the MessageQueue
, which will be executed after UI_ANIMATION_DELAY
milliseconds (let's say it is 300ms).
Now, when you are performing consecutive clicks you are posting events in this way:
SHOW - HIDE - SHOW - HIDE - ...
If you do not perform removeCallbacks()
, all of these messages will be executed, meaning that each of those SHOW
and HIDE
actions would be performed, which results in such a glitchy behavior.
On the other hand, when using removeCallbacks()
you are telling that you are no longer interested in the opposite event and do not want that event to be executed entirely. For example, if we have a situation when system bars are shown, then the next click would initiate a HIDE
event to happen after 300 ms and you are explicitly telling, that "hey, if there are some events posted that should SHOW
the system bar, then cancel them"
handler.removeCallbacks(showRunnable);
handler.postDelayed(hide, 300);
What this gives you, is that each time you perform consecutive click events, the opposite event message that was already posted on the queue would be cancelled. This assures, that each time only 1 message is posted on the queue.
System UI is visible, current message queue:
EMPTY
Click happens:
HIDE
Click happens:
SHOW (HIDE is being removed from queue)
Click happens:
HIDE (SHOW is being removed from queue)
Thus, at the end, when 300ms are passed and this message is not removed from queue, only the last event would be executed.