안드로이드 자바

[Java][Android] 버튼 연속 클릭 방지하기

teamnova 2025. 6. 2. 15:58
728x90

왜 버튼 연속 클릭 방지가 필요한가요?

서버 부하 증가: 사용자가 버튼을 빠르게 여러 번 누르면, 각 클릭마다 서버로 API 요청이 중복해서 전송될 수 있습니다. 이는 서버 리소스를 불필요하게 소모시키고, 심한 경우 서비스 장애로 이어질 수 있습니다.

의도치 않은 데이터 중복 생성/수정: 예를 들어 '게시글 작성' 버튼을 연타하면 동일한 내용의 게시글이 여러 개 생성될 수 있습니다.
사용자 경험(UX) 저하: 앱이 반복적인 요청으로 인해 느려지거나, 예기치 않은 동작을 보이면 사용자는 불편함을 느낍니다.

클라이언트 리소스 낭비: 불필요한 네트워크 요청은 사용자의 데이터 소모를 늘리고, 배터리 사용량에도 영향을 줄 수 있습니다.

 

1.마지막 클릭 시간으로 연속 클릭 방지 (Throttling)

마지막으로 유효한 클릭이 발생한 시간을 기록하고, 다음 클릭이 너무 짧은 시간 내에 발생하면 해당 클릭 이벤트를 무시하는 것입니다. 이를 '쓰로틀링(Throttling)'의 한 형태로 볼 수 있습니다.

 

2. 버튼 비활성화 활성화로 연속 클릭 방지

사용자가 버튼을 클릭하면 즉시 버튼을 비활성화(disabled) 상태로 만들고, 서버 통신 또는 지정된 작업이 완료되거나 일정 시간이 지난 후 다시 활성화(enabled)하는 방식입니다. 이는 사용자에게 시각적으로 버튼이 현재 동작 중이거나 일시적으로 사용할 수 없음을 알려줍니다.

 

 

예제코드

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <Button
        android:id="@+id/myThrottlingButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="클릭 (시간 간격 체크)" />

    <Button
        android:id="@+id/myDisableEnableButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="클릭 (비활성화/활성화)" />


</LinearLayout>

 

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private Button myThrottlingButton, myDisableEnableButton;
    private long lastClickTime = 0; // 마지막으로 유효하게 클릭된 시간
    private static final long CLICK_TIME_INTERVAL = 3000; // 3초 (밀리초 단위) - 이 시간 내의 클릭은 무시
    private static final long DISABLE_DURATION = 1500; // 1.5초 동안 비활성화

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

        myThrottlingButton = findViewById(R.id.myThrottlingButton);
        myDisableEnableButton = findViewById(R.id.myDisableEnableButton);

        myThrottlingButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 현재 시간과 마지막 클릭 시간 비교
                if (SystemClock.elapsedRealtime() - lastClickTime < CLICK_TIME_INTERVAL) {
                    Log.d("ButtonClick", "연타 방지: 너무 빠른 클릭입니다.");
                    Toast.makeText(MainActivity.this, "너무 빠른 클릭입니다. 잠시후 시도해 주세요", Toast.LENGTH_SHORT).show();
                    return; // 클릭 이벤트 무시
                }
                // 유효한 클릭이므로, 마지막 클릭 시간을 현재 시간으로 업데이트
                lastClickTime = SystemClock.elapsedRealtime();

                // 실제 클릭 처리 로직 (예: 서버 통신)
                Log.d("ButtonClick", "버튼 클릭됨! 서버 통신 시작...");
                performServerCommunication("시간 간격 체크 방식");
            }
        });

        myDisableEnableButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myDisableEnableButton.setEnabled(false); // 버튼 즉시 비활성화

                // 실제 클릭 처리 로직 (예: 서버 통신)
                Log.d("ButtonClick", "비활성화 버튼 클릭됨! 서버 통신 시작...");
                performServerCommunication("비활성화/활성화 방식");

                // 일정 시간 후 버튼 다시 활성화 (UI 스레드에서 실행)
                new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        // Activity가 아직 살아있고 버튼이 존재할 때만 활성화 (선택적이지만 안전)
                        if (myDisableEnableButton != null && !isFinishing()) {
                            myDisableEnableButton.setEnabled(true);
                        }
                    }
                }, DISABLE_DURATION);
            }
        });
    }

    private void performServerCommunication(String method) {
        // 여기에 실제 서버와 통신하는 코드를 넣습니다.
        Toast.makeText(this, method + ": 서버와 통신하거나 다른 작업을 수행합니다.", Toast.LENGTH_SHORT).show();
    }
}

 

시연영상