お手軽にAndroidのButtonの連打を防止してみた

# 目的
- Androidアプリにおいて、ボタンを連打されると困るので、連打できないようにしたい。



# 実装!
## Button(AppCompatButton)を継承したButtonクラスを追加
```java:app/src/main/java/com/example/barrageguardbuttondemo/utils/BarrageGuardButton.java
package com.example.barrageguardbuttondemo.utils; // Replace with your package

import android.content.Context;
import android.os.Handler;
import android.support.v7.widget.AppCompatButton;
import android.util.AttributeSet;
import android.view.View;

/**
 * 連打防止Buttonクラス
 */
public class BarrageGuardButton extends AppCompatButton {
    public BarrageGuardButton(Context context) {
        super(context);
    }

    public BarrageGuardButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BarrageGuardButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setOnClickListener(final View.OnClickListener listener) {
        super.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View view) {

                view.setEnabled(false);
                new Handler().postDelayed(new Runnable() {
                    public void run() {
                        view.setEnabled(true);
                    }
                }, 3000L);

                listener.onClick(view);
            }
        });
    }
}
```

## Layout xml にButtonを追加 or 既存のボタンのタグを置換
```xml:app/src/main/res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:gravity="center"
  tools:context="com.example.barrageguardbuttondemo.MainActivity">

  <com.example.barrageguardbuttondemo.utils.BarrageGuardButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click here"/>
</LinearLayout>
```

## ClickListenerをセット
```java:app/src/main/java/com/example/barrageguardbuttondemo/MainActivity.java
package com.example.barrageguardbuttondemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.example.barrageguardbuttondemo.utils.BarrageGuardButton;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ((BarrageGuardButton) findViewById(R.id.button1)).setOnClickListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(MainActivity.this, "It works!!!", Toast.LENGTH_SHORT).show();
                }
            });
    }
}
```

以上で完了です！これでボタンをタップすると一定時間enabled:falseになり、連打ができなくなります。
既存コードで実装する場合は、xmlのButtonタグを置換するだけで振る舞いを変えることができます。

## おまけ
`BarrageGuardButton` は Buttonクラス(今回は `android.support.v7.widget.AppCompatButton` ) を継承しているので、そのままDataBindingの表記にも対応できます。

```groovy:app/build.gradle
apply plugin: 'com.android.application'

android {

    ...

    dataBinding {
      enabled = true
    }
}
```

```xml:app/src/main/res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools">

  <data>
    <variable
      name="activity"
      type="com.example.barrageguardbuttondemo.MainActivity"/>
  </data>

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context="com.example.barrageguardbuttondemo.MainActivity">

    <com.example.barrageguardbuttondemo.utils.BarrageGuardButton
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:onClick="@{activity::onClickDemoButton}"
      android:text="Click here"/>
  </LinearLayout>
</layout>
```

```java:app/src/main/java/com/example/barrageguardbuttondemo/MainActivity.java
package com.example.barrageguardbuttondemo;

import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.example.barrageguardbuttondemo.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setActivity(this);
    }

    public void onClickDemoButton(View view) {
        Toast.makeText(MainActivity.this, "It works!!!", Toast.LENGTH_SHORT).show();
    }
}
```
こんな感じに書いてもバッチリ動作します！

DataBindingについてはこちら : [https://developer.android.com](https://developer.android.com/topic/libraries/data-binding/index.html?hl=ja)
(日本語の方もだいぶ整ってきましたね)

一応サンプルプロジェクトをGitHubで公開しています : https://github.com/sasakii/BarrageGuardButtonDemo

# 動作確認
![demo](https://github.com/sasakii/BarrageGuardButtonDemo/raw/master/gallery/demo.gif)
※ GIFにしたせいで若干汚いですがご了承を