Зачем использовать removeCallbacks() с postDelayed()?

Я пытаюсь понять функциональность, и, в частности, одну конкретную причину, почему мы используем removeCallbacks()в сочетании с postDelayed() пройдя по шаблону полноэкранного режима, предоставленному в Android Studio. В полноэкранном шаблоне действий при прикосновении к экрану он показывает / скрывает строку состояния и панель навигации / системную панель через определенное количество миллисекунд, а в случае этого шаблона - 3000 миллисекунд.


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

Я это понимаю removeCallbacks() используется для удаления ожидающих сообщений /runnables из очереди сообщений, но есть ли какая-то особая причина, по которой мы будем использовать его, кроме случаев, когда выполняется условие и мы больше не хотим, чтобы ожидающие сообщения /runnables выполнялись?

Я спрашиваю об этом, потому что в отношении шаблона полноэкранного режима я немного запутался, так как кажется, что если я не позвоню mHideHandler.removeCallbacks(Runnable) когда используешь postDelayed() тогда это позволит пользователю спамить методы скрытия / показа. При рассылке спама похоже, что анимация перехода прервана, и что анимация может даже застрять во время спама, потому что она была остановлена ​​в определенной точке во время перехода. Однако, если я позвоню mHideHandler.removeCallbacks(Runnable) прямо перед postDelayed() тогда это предотвратит спам пользователей методами скрытия / показа, что хорошо.

Я думаю, вкратце, мой вопрос, как это mHideHandler.removeCallbacks(Runnable) предотвратить спам, вызываемый при использовании с postDelayed()? Вопрос похож на этот вопрос, но я надеюсь получить объяснение, почему это происходит.

Вот различия в формате.gif. Использование removeCallbacks() является предполагаемым поведением, а комментирование removeCallbacks() приводит к нежелательному поведению "злоупотребления":

С помощью removeCallbacks()

Без removeCallbacks()

РЕДАКТИРОВАТЬ: Добавлено в.gifs и добавлены комментарии к removeCallbacks() в коде, чтобы помочь определить, о какой части кода я говорю.

1 ответ

Решение

Каждый раз, когда вы выполняете клик, вы публикуете событие на MessageQueue, который будет выполнен после UI_ANIMATION_DELAY миллисекунды (скажем, это 300 мс).

Теперь, когда вы выполняете последовательные клики, вы публикуете события следующим образом:

SHOW - HIDE - SHOW - HIDE - ...

Если вы не выполняете removeCallbacks() все эти сообщения будут выполнены, а это означает, что каждый из SHOW а также HIDE действия будут выполнены, что приведет к такому глючному поведению.

С другой стороны, при использовании removeCallbacks() вы говорите, что вы больше не заинтересованы в противоположном событии и не хотите, чтобы это событие выполнялось полностью. Например, если у нас есть ситуация, когда отображаются системные панели, то следующий щелчок инициирует HIDE событие произойдет через 300 мс, и вы явно говорите, что "эй, если есть какие-то события, которые должны SHOW системная панель, затем отмените их

handler.removeCallbacks(showRunnable);
handler.postDelayed(hide, 300);

Это дает вам то, что каждый раз, когда вы выполняете последовательные события щелчка, сообщение о противоположном событии, которое уже было размещено в очереди, будет отменено. Это гарантирует, что каждый раз в очереди размещается только 1 сообщение.

Системный интерфейс видим, текущая очередь сообщений:

EMPTY

Клик происходит:

HIDE

Клик происходит:

SHOW (HIDE is being removed from queue)

Клик происходит:

HIDE (SHOW is being removed from queue)

Таким образом, в конце, когда пройдено 300 мс и это сообщение не удалено из очереди, будет выполнено только последнее событие.

Другие вопросы по тегам