📌

【Kotlin】Androidアプリでボタン連打を抑止する方法(DataBinding編)

2021/03/13に公開

この記事はKotlin Advent Calendar 2020の 5 日目の記事です。
Android アプリ開発初心者ですが、空きがあったので勢いだけで参加してみました。(1 日ぶり 2 回目)

はじめに

Android に限らず色々なアプリを開発していて、ついつい忘れがちなボタン連打対策。。。
処理の多重実行によってバグが発生することも多々あるため対処が必要です。

いざ実装しようと調べて見ると、通常の連打対策の記事はよくありますが、
DataBinding を利用しているプロジェクトで、簡単に導入できる方法が見つからなかったため、備忘録として記事にしようと思います。

DataBinding を使った場合の通常のボタン押下処理

android:onClickを利用してボタン押下時処理と紐付けを行います。

MainLayout.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools">
  <data>
    <variable name="viewModel" type="com.sample.viewmodel.MainViewModel" />
  </data>
  <LinearLayout>
    <Button
      android:onClick="@{() -> viewModel.onClickButton()}"
    />
  </LinearLayout>
</layout>

※ 実際は幅、高さなどの属性も指定しないとエラーになりますが、今回の説明に不要な部分は省略してあります。

連打対策済みボタン押下時処理

Extension を利用し全てのビューの基底クラスに
OnClickListener のセッターのラッパー(連打防止が処理入り)を定義し、
カスタム属性と紐付けます。

ViewExtension.kt
package com.sample.extension

import android.view.View
import androidx.databinding.BindingAdapter
/**
 * ==============================================
 *  View Extensions
 * ==============================================
 */
/**
 * setOnSingleClickListener
 */
@BindingAdapter("android:onSingleClick")
fun View.setOnSingleClickListener(listener: View.OnClickListener) {
  // 押下後一時的に押下処理を無効化する時間(ms)
  val delayMillis = 500L
  // 前回押下時間(タイムスタンプ, ms)
  var pushedAt = 0L

  this.setOnClickListener {
    if (System.currentTimeMillis() - pushedAt < delayMillis) {
      // 前回押下から規定時間分経過していない場合は、処理終了
      return@setOnClickListener
    }
    // 押下時間を更新
    pushedAt = System.currentTimeMillis()
    // 押下時処理を実行
    listener.onClick(this)
    return@setOnClickListener
  }
}

レイアウトでの利用方法はandroid:onClickの代わりに利用するだけです。

MainLayout.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools">
  <data>
    <variable name="viewModel" type="com.sample.viewmodel.MainViewModel" />
  </data>
  <LinearLayout>
    <Button
      android:onSingleClick="@{() -> viewModel.onClickButton()}"
    />
  </LinearLayout>
</layout>

さいごに

次からは初期段階から導入するように注意します....
私の場合、気づいたときには、android:onClickが既に 100 箇所以上定義されていたので、少しの書き換えで済んで良かった。。。

参考記事

GitHubで編集を提案
株式会社ナンバーフォー

Discussion