Работа с быстрым нажатием кнопок

У меня есть кнопка с OnClickListener. Для иллюстративных целей рассмотрим кнопку, которая показывает модальный диалог:

public class SomeActivity ... {

  protected void onCreate(Bundle state) {
    super.onCreate(state);

    findViewById(R.id.ok_button).setOnClickListener(
      new View.OnClickListener() {
        public void onClick(View v) {
          // This should block input
          new AlertDialog.Builder(SomeActivity.this)
            .setCancelable(true)
            .show();
      }
    });
}

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

Но иногда кнопка OnClickListener вызывается дважды, прежде чем появится диалоговое окно. Вы можете легко воспроизвести это достаточно быстро, нажав на кнопку очень быстро. Обычно я должен попробовать несколько раз, прежде чем это произойдет, но рано или поздно я вызову несколько вызовов onClick (...) до ввода диалоговых блоков.

Я вижу это поведение в Android 2.1 на телефоне Motorola Droid. Мы получили 4 отчета о сбоях на рынке, указав, что это случается с людьми.

В зависимости от того, что делают наши OnClickListeners, это приводит к разным хаосам. Как мы можем гарантировать, что блокирующие диалоги фактически блокируют ввод после первого нажатия?

Ответ 1

Ромени Гай подтвердил, что это действительно ошибка в Android: "Это происходит, только если пользователю удастся дважды нажать кнопку в < 125 мс. Я считаю, что мы исправили эту возможную ошибку в Froyo".

Мы будем использовать шаблон "Стеклянная панель", чтобы обойти ошибку на старых ОС. То есть мы рассмотрим экран с невидимым видом. После первого события клика мы сделаем вид "видимым", чтобы он перехватывал последующие события касания.

Этого недостаточно, чтобы предотвратить дальнейшие события только на одной кнопке. Вам нужно заблокировать все последующие события для всей активности до тех пор, пока диалог не будет отклонен, активность не будет возобновлена ​​и т.д., После чего вы снова сделаете стеклянную панель "невидимой".

Если это не сработает, нам просто нужно будет жить с этим и лучше переносить неожиданные дополнительные события.

Ответ 2

Спасибо за попытку, mdma, но это проблема платформы, а не проблема с нашим кодом. Хуже того, по-видимому, это не проблема, которая может быть проработана в пользовательском коде (для этого требуются детали из драйвера сенсорного экрана, которые не передаются вместе). Кроме того, ваш пример кода не делает то, что вы думаете. show() не отображает диалоговое окно немедленно. Он добавляет сообщение в конец очереди событий, которое в конечном итоге отображает диалог. Больше событий касания может уже находиться в очереди, ожидающей выполнения после возвращения onClick().

Я не уверен, почему люди голосуют за ответ.