Android prevent double click

Блокировка двойного клика. Велосипед?

С чего началось

В очередной раз копаясь с легаси кодом и борясь с утечкой контекста я сломал в приложении блокировку двойного клика на кнопке. Пришлось искать, что именно я сломал и как это было реализовано. С учетом того, что в основном для подобной блокировки предлагается либо отключать сам UI элемент либо просто игнорировать последующие клики в течении небольшого промежутка времени, существующее решение показалось мне довольно интересным с т.з. компоновки кода. Но оно все равно требовало создавать списки кнопок и писать довольно много поддерживающего кода. Создать экземпляр класса, который будет хранить список элементов, заполнить его, в каждом обработчике клика вызывать три метода. В общем, много мест, где можно что-нибудь забыть или перепутать. А я не люблю ничего помнить. Каждый раз когда мне кажется что я что-то помню, оказывается, что либо я помню неправильно, либо кто-то это уже переделал по другому.

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

В общем, природная лень заставила задуматься, а можно ли сделать без всего этого? Ну чтобы заблокировал кнопку и забыл. А оно там само дальше будет работать как надо. Сначала появилась мысль, что наверняка уже есть какая-нибудь библиотека, которую можно подключить и надо будет вызывать всего один метод типа — sdelayMneHorosho().

Но опять же, человек я в определенном смысле старой закалки и поэтому не люблю всякие лишние зависимости. Зоопарк библиотек и кодогенерации вызывает у меня уныние и разочарование в человечестве. Ну и поверхностное гугление находило только типичные варианты с таймерами или их вариациями.

Еще, наверное можно просто выключать элемент первой строкой в обработчике, а потом включать. Проблема только в том, что это потом наступает не всегда тривиально и в этом случае необходимо добавлять вызов кода «включения» в конце всех вариантов исполнения, к которым может привести нажатие кнопки. Неудивительно, что такие решения у меня с ходу не нагуглились. Очень уж запутанные они и поддерживать их крайне сложно.

Захотелось сделать проще, универсальнее, и чтобы помнить надо было как можно меньше.

Решение из проекта

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

Класс небольшой и в принципе понятно что он делает. В двух словах, для того, чтобы заблокировать кнопку на какой-нибудь активити или фрагменте, нужно создать экземпляр класса MultiClickFilter и заполнить его список UI элементами, которые надо блокировать. Можно сделать несколько списков, но в этом случае обработчик каждого элемента должен «знать» какой экземпляр «кликфильтра» дергать.

Кроме того, он не позволяет просто проигнорировать клик. Для этого обязательно надо заблокировать весь список элементов, а потом, следовательно, его обязательно надо разблокировать. Это приводит к дополнительному коду который надо добавить в каждый обработчик. Да и в примере я бы метод unlockButtons поместил в блок finally, а то мало ли… В общем, это решение вызывает вопросы.

Новое решение

В общем, понимая, что наверное не будет какой-то серебряной пули, в качестве исходных посылок было принято:

  1. Разделять списки блокируемых кнопок не целесообразно. Ну не смог я придумать никакого примера, требующего такого разделения.
  2. Не отключать элемент (enabled/clickable) чтобы сохранить анимации и вообще живость элемента
  3. Блокировать клик в любом обработчике, который для этого предназначен, т.к. предполагается, что адекватный пользователь не кликает куда попало как из пулемета, а для предотвращения случайного «дребезга» достаточно просто отключить обработку кликов на несколько сотен миллисекунд «для всех»
Читайте также:  Тест для планшета андроид

Значит, в идеале, у нас должна быть одна точка в коде, где происходит вся обработка и один метод, который будет дергаться из любого места проекта в любом обработчике и будет блокировать обработку повторных нажатий. Предположим, что наш UI не подразумевает, что пользователь кликает чаще чем два раза в секунду. Не, если это необходимо, то видимо придется отдельно уделять внимание производительности, у нас же случай простой, чтобы дрожащими от восторга пальцами нельзя было уронить приложение на нереинтерабельной функции. А также, чтобы не надо было каждый раз париться над оптимизацией производительности простого перехода с одной активити на другую или каждый раз мелькать диалогом прогресса.

Все это у нас будет работать в главном потоке, так что нам не надо беспокоится о синхронизации. Также, фактически, мы можем перенести проверку на то, надо ли нам обработать клик или проигнорировать его, в этот самый метод. Ну, если получится, то можно было бы и сделать интервал блокировки настраиваемым. Так чтобы в совсем нехорошем случае можно было увеличить интервал для конкретного обработчика.

Возможно ли это?

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

Если клик подлежит обработке, то установится блокировка на заданное время (или по умолчанию). Метод позволят не думать о списках элементов, не строить сложные проверки и не управлять доступностью UI элементов вручную. Предлагаю обсудить в комментариях эту реализацию, возможно есть лучшие варианты?

Источник

Android Предотвращение двойного нажатия на кнопку

Каков наилучший способ предотвратить двойные нажатия кнопки на Android?

ОТВЕТЫ

Ответ 1

Отключить кнопку с помощью setEnabled(false) , пока пользователь не сможет снова щелкнуть его.

Ответ 2

сохранение последнего клика, когда щелчок предотвратит эту проблему.

Ответ 3

Использование похоже на OnClickListener, но вместо этого переопределяет onSingleClick():

Ответ 4

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

Использование такое же, как и OnClickListener, но вместо OnOneClick() вместо этого:

Ответ 5

Вы можете сделать это очень причудливым способом с помощью функций расширения Kotlin и RxBinding

Ответ 6

Я также запускаю аналогичную проблему, я показывал некоторые datepicker и timepickers, где иногда он нажимал 2 раза. Я решил это этим

Вы можете изменить время в зависимости от вашего требования. Этот метод работает для меня.

Ответ 7

setEnabled(false) отлично работает для меня.

Идея заключается в том, что я пишу < setEnabled(true); >в начале и просто делаю ее false при первом нажатии кнопки.

Ответ 8

Фактическое решение этой проблемы — использовать setEnabled (false), который выделяет кнопку, и setClickable (false), который делает так, что второй клик не может быть получен. Я протестировал это и, похоже, очень эффективен.

Ответ 9

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

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

и чтобы вызвать это просто сделайте это:

или укажите собственную задержку:

ОБНОВЛЕНИЕ: Выше немного старомодно сейчас, когда RxJava настолько распространен. как уже упоминали другие, в Android мы могли бы использовать дроссель, чтобы замедлить щелчки. вот один пример:

Читайте также:  Save navigation on android

Вы можете использовать эту библиотеку для этого: implementation ‘com.jakewharton.rxbinding2:rxbinding:2.0.0’

Ответ 10

Я знаю, это старый вопрос, но я разделяю лучшее решение, которое я нашел, чтобы решить эту общую проблему.

И в другом файле, например Utils.java

Ответ 11

Мое решение состоит в том, чтобы попытаться использовать boolean переменную:

И используя как ниже:

Ответ 12

Нажмите Guard хорошо работает с Butter Knife

Ответ 13

Расширение Kotlin, позволяющее получить краткий встроенный код и переменное время ожидания двойного щелчка

Ответ 14

Кажется, что установка ваших слушателей кликов в onResume и обнуление их в onPause тоже делает трюк.

Ответ 15

Мне только помогло вспомнить временную метку и проверить ее (прошло более 1 секунды с предыдущего клика).

Ответ 16

Надеюсь, это поможет вам, поместите код в обработчик событий.

Ответ 17

Я обнаружил, что ни одно из этих предложений не работает, если метод onClick не возвращается немедленно. Событие touch помещено в очередь Android, а следующий onClick вызывается только после завершения первого. (Так как это делается в одном потоке пользовательского интерфейса, это действительно нормально.) Мне нужно было использовать время, когда функция onClick завершена + одна логическая переменная, чтобы отметить, работает ли данный onClick. Оба эти атрибута маркера являются статическими, чтобы избежать одновременного запуска любого onClickListener. (Если пользователь нажимает на другую кнопку) Вы можете просто заменить свой OnClickListener на этот класс и вместо того, чтобы внедрять метод onClick, вам нужно реализовать абстрактный метод oneClick().

Ответ 18

Если кто-то все еще ищет короткий ответ, вы можете использовать следующий код

Этот код будет идти внутри if statement всякий раз, когда пользователь нажимает на представление в View within 1 second а затем на return; будет инициирован и дальнейший код не будет инициирован.

Ответ 19

Настройка Clickable to false не работает при первом двойном щелчке, но последующие двойные щелчки блокируются. Как будто делегат щелчка по загрузке в первый раз работает медленнее, а второй клик захватывается до первого завершения.

Ответ 20

Я исправляю эту проблему, используя две кланы, одну из которых похожа на @jinshiyi11 answer, а анотер основан на явном щелчке, в этом случае вы можете щелкнуть кнопку только один раз, если вы хотите еще один щелчок, вы должны явно указать его.

Ответ 21

Ответ 22

Ответ 23

Попробуйте, он работает:

Ответ 24

вы также можете использовать rx привязки jake wharton для этого. вот образец, который прокладывает 2 секунды между последовательными нажатиями:

//note: игнорировать Object v в этом случае, и я всегда думаю.

Ответ 25

Вы можете использовать этот метод. Используя пост-задержку вы можете позаботиться о событиях двойного щелчка.

void debounceEffectForClick (View view) <

Ответ 26

Мы могли бы использовать только что синхронизированную кнопку:

Ответ 27

Если вы не хотите (или не можете) использовать флаги boolean или переопределять onClickListener , вы также можете попытаться объявить свою активность с помощью android:launchMode=»singleTop» в AndroidManifest.xml.

Как это работает?

  • Если экземпляр действия находится в верхней части стека — новый активность не будет создана, вместо этого будет вызываться onNewIntent().
  • Активность может иметь несколько экземпляров
  • Экземпляры могут находиться в разных задачах.
  • Одна задача может иметь несколько экземпляров

Ответ 28

Я предпочитаю использовать блок семафора. Он потокобезопасен и может использоваться не только для кнопок.

Пример кода прост:

Ответ 29

Если только кнопка запускает новую деятельность, проблема может быть решена с помощью singleTop «режим запуска активации» и FLAG_ACTIVITY_CLEAR_TOP, заданное в намерении. Это не будет работать в случае сложной иерархии активности, но может использоваться для простой древовидной структуры приложения.

Источник

Android предотвращает двойной щелчок по кнопке

Каков наилучший способ предотвратить двойное нажатие на кнопку в Android?

Отключите кнопку, setEnabled(false) пока пользователь не сможет снова нажать ее.

сохранение последнего щелчка при нажатии предотвратит эту проблему.

Читайте также:  Зашифрованные сообщения для андроид

Использование аналогично OnClickListener, но вместо этого переопределяет onSingleClick ():

Отключение кнопки или настройка unclickable не достаточно, если вы выполняете интенсивную вычислительную работу в onClick (), поскольку события щелчка могут быть поставлены в очередь, прежде чем кнопка может быть отключена. Я написал абстрактный базовый класс, который реализует OnClickListener, который вы можете вместо этого переопределить, чтобы решить эту проблему, игнорируя любые щелчки в очереди:

Использование такое же, как OnClickListener, но вместо этого переопределяет OnOneClick ():

Вы можете сделать это очень причудливым способом с помощью функций расширения Kotlin и RxBinding

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

Вы можете изменить время в зависимости от ваших требований. Этот метод работает для меня.

setEnabled(false) отлично работает для меня

Идея в том, что я пишу < setEnabled(true); >в начале и просто делаю это false по первому нажатию кнопки.

Я знаю, что это старый вопрос, но я разделяю лучшее решение, которое я нашел, чтобы решить эту общую проблему

И в другом файле, как Utils.java

Фактическое решение этой проблемы состоит в том, чтобы использовать setEnabled (false), который скрывает кнопку, и setClickable (false), который делает его таким, что второй щелчок не может быть получен. Я проверил это, и это кажется очень эффективным.

Если кто-то все еще ищет короткий ответ, вы можете использовать следующий код

Этот код будет входить в if statement каждый раз, когда пользователь нажимает на, View within 1 second а затем return; будет инициирован, и дальнейший код не будет инициирован.

K скудного Котлин идиоматический способ:

Мое решение — попытаться использовать boolean переменную:

И используя как ниже:

ОБНОВЛЕНИЕ : решение Kotlin, используя расширение представления

Click Guard хорошо работает с ножом для масла

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

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

и чтобы вызвать это просто сделайте это:

или укажите собственную задержку:

ОБНОВЛЕНИЕ: Выше немного старомодно сейчас, когда RxJava настолько распространен. как уже упоминали другие, в Android мы могли бы использовать дроссель, чтобы замедлить щелчки. вот один пример:

Вы можете использовать эту библиотеку для этого: implementation ‘com.jakewharton.rxbinding2:rxbinding:2.0.0’

Вы можете использовать этот метод. Используя пост-задержку, вы можете позаботиться о событиях двойного щелчка.

void debounceEffectForClick (View view) <

Расширение Kotlin, позволяющее получить краткий встроенный код и переменное время ожидания двойного щелчка

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

Кажется, что установка прослушивателей щелчков в onResume и обнуление их в onPause тоже помогает.

Для меня помогло только помнить временную метку и проверять ее (что прошло более 1 секунды с момента предыдущего клика).

Я надеюсь, что это может помочь вам, поместите код в ваш обработчик событий.

Я обнаружил, что ни одно из этих предложений не работает, если метод onClick не возвращается немедленно. Android-событие ставится в очередь, и следующий onClick вызывается только после завершения первого. (Так как это делается в одном потоке пользовательского интерфейса, это действительно нормально.) Мне нужно было использовать время завершения функции onClick + одну логическую переменную, чтобы указать, работает ли данный onClick. Оба эти атрибута маркера являются статическими, чтобы избежать одновременного запуска onClickListener. (Если пользователь нажимает на другую кнопку) Вы можете просто заменить свой OnClickListener на этот класс, и вместо реализации метода onClick вам нужно реализовать абстрактный метод oneClick ().

Вы также можете использовать rx-привязки Джейка Уортона для достижения этой цели. Вот пример, который добавляет 2 секунды между последовательными щелчками:

// примечание: игнорировать Object v в этом случае, и я думаю, что всегда.

Источник

Оцените статью