Android : 버튼 클릭 처리 방법


95

비 Java 및 비 Android 영역에서 탄탄한 경험을 쌓은 저는 Android를 배우고 있습니다.

다른 영역과 많은 혼동이 있습니다. 그중 하나는 버튼 클릭을 처리하는 방법입니다. 최소한 4 가지 방법 (!!!)이 있으며 여기에 간략하게 나열되어 있습니다.

일관성을 위해 다음과 같이 나열합니다.

  1. View.OnClickListener활동에 클래스 의 멤버를 onClick두고 onCreate활동 메소드의 논리를 처리 할 인스턴스에 할당합니다 .

  2. 'onCreate'액티비티 메서드에서 'onClickListener'를 생성하고 setOnClickListener를 사용하여 버튼에 할당합니다.

  3. 활동 자체에서 'onClickListener'를 구현하고 'this'를 버튼의 리스너로 지정하십시오. 활동에 버튼이 적은 경우 버튼 ID를 분석하여 적절한 버튼에 대한 'onClick'핸들러를 실행해야합니다.

  4. 'onClick'로직을 구현하는 활동에 대한 공용 메소드를 가지고 활동 xml 선언의 단추에 할당합니다.

질문 1:

그 모든 방법이 있습니까? 다른 옵션이 있습니까? (다른 건 필요 없어 그냥 궁금해)

나에게 가장 직관적 인 방법은 최신 방법 일 것입니다. 입력 할 코드의 양이 가장 적고 가장 읽기 쉽습니다 (적어도 나에게는).

하지만이 접근 방식이 널리 사용되는 것은 아닙니다. 그것을 사용하는 것에 대한 단점은 무엇입니까?

질문 # 2 :

각 방법의 장단점은 무엇입니까? 귀하의 경험이나 좋은 링크를 공유하십시오.

모든 피드백을 환영합니다!

추신 : Google에이 주제에 대한 무언가를 찾아 보려고했지만 내가 찾은 유일한 것은 "어떻게"그 일을 수행하는지 설명하는 것이지 왜 좋은지 나쁜지가 아닙니다.

답변:


147

질문 1 : 안타깝게도 당신이 가장 직관적이라고 말하는 것은 안드로이드에서 가장 적게 사용되는 것입니다. 이해했듯이 UI (XML)와 계산 기능 (Java 클래스 파일)을 분리해야합니다. 또한 더 쉽게 디버깅 할 수 있습니다. 실제로 이런 식으로 읽고 Android imo에 대해 생각하는 것이 훨씬 쉽습니다.

질문 2 : 주로 사용되는 두 가지는 # 2와 # 3이라고 생각합니다. 예를 들어 Button clickButton을 사용하겠습니다.

2

익명 클래스의 형태입니다.

Button clickButton = (Button) findViewById(R.id.clickButton);
clickButton.setOnClickListener( new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                ***Do what you want with the click here***
            }
        });

이것은 findViewById로 버튼 변수가 설정된 바로 옆에 onClick 메서드가 있기 때문에 제가 가장 좋아하는 것입니다. 이 clickButton Button View를 다루는 모든 것이 여기에 있다는 것이 매우 깔끔하고 깔끔해 보입니다.

내 동료가 말한 단점은 onclick 리스너가 필요한 뷰가 많다는 것입니다. onCreate의 길이가 매우 길다는 것을 알 수 있습니다. 그래서 그가 사용하는 것을 좋아하는 이유 :

5 개의 clickButton이 있다고 가정 해 보겠습니다.

Activity / Fragment가 OnClickListener를 구현하는지 확인하십시오.

// in OnCreate

Button mClickButton1 = (Button)findViewById(R.id.clickButton1);
mClickButton1.setOnClickListener(this);
Button mClickButton2 = (Button)findViewById(R.id.clickButton2);
mClickButton2.setOnClickListener(this);
Button mClickButton3 = (Button)findViewById(R.id.clickButton3);
mClickButton3.setOnClickListener(this);
Button mClickButton4 = (Button)findViewById(R.id.clickButton4);
mClickButton4.setOnClickListener(this);
Button mClickButton5 = (Button)findViewById(R.id.clickButton5);
mClickButton5.setOnClickListener(this);


// somewhere else in your code

public void onClick(View v) {
    switch (v.getId()) {
        case  R.id.clickButton1: {
            // do something for button 1 click
            break;
        }

        case R.id.clickButton2: {
            // do something for button 2 click
            break;
        }

        //.... etc
    }
}

내 동료가 설명하는이 방법은 모든 onClick 계산이 onCreate 메소드를 복잡하게하지 않고 한곳에서 처리되므로 그의 눈에는 깔끔합니다. 그러나 내가 보는 단점은 다음과 같습니다.

  1. 자신을 바라보고,
  2. onClick 메서드에서 사용하는 onCreate에있을 수있는 다른 개체는 필드로 만들어야합니다.

더 많은 정보를 원하시면 알려주세요. 꽤 긴 질문이기 때문에 귀하의 질문에 완전히 대답하지 않았습니다. 그리고 사이트를 찾으면 답을 넓힐 것입니다. 지금은 경험을 제공하고 있습니다.


1
옵션 2의 경우 다음과 같이 만들 수 있습니다. clickButton.setOnClickListener (new View.OnClickListener () {@Override public void onClick (View v) {// TODO what you want to do}}); 도움말은 OnClickListener를 해결
ColossalChris

옵션 3은 아마도 MVP 패턴으로 가장 깨끗하고 확장하기 쉬운 것입니다.
Raffaeu

옵션 2는 여전히 onCreate()끔찍하게 길지 않은 것을 생산할 수 있습니다 . 클릭 리스너 할당 및 익명 클래스는에서 호출되는 별도의 도우미 메서드로 분리 될 수 있습니다 onCreate().
닉 알렉 세 에프

@Colossal : 당신은 그것을 할 필요가 없습니다. "implements View.OnClickListener"와 같은 활동 클래스에 확장을 추가합니다.
TomeeNS 2011

10

# 1 레이아웃에 생성되지 않은 버튼이있을 때 마지막 버튼을 자주 사용합니다.

ProGuard와 같은 소스 난독 처리기 를 사용할 때 난독 화 되지 않도록 활동에 이러한 메서드를 표시해야 하므로 실제로 사용하고 비즈니스 응용 프로그램에서 사용하는 경우 여기에 특히주의하십시오 .

이 접근 방식을 사용하여 일종의 컴파일 시간 보안을 보관하려면 Android Lint ( 예제 )를 살펴보세요 .


# 2 모든 방법의 장단점 은 거의 동일하며 교훈은 다음과 같아야합니다.

가장 적합하거나 가장 직관적 인 것을 사용하십시오.

OnClickListener여러 버튼 인스턴스에 동일한 항목을 할당해야하는 경우 클래스 범위 (# 1)에 저장합니다. Button에 대한 간단한 리스너가 필요한 경우 익명으로 구현하십시오.

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Take action.
    }
});

나는 OnClickListener활동에서를 구현하지 않는 경향 이 있습니다. 이것은 때때로 약간 혼란스러워집니다 (특히 여러 다른 이벤트 핸들러를 구현하고 아무도 무엇을 this하고 있는지 아무도 모르는 경우 ).


나는 동일하지만 여전히 기능에 대한 출력을 얻지 못하고 있습니다. 내 코드와 쿼리는 여기에 있습니다. stackoverflow.com/questions/25107427/…
Rocket

8

나는 옵션 4를 선호하지만 Grails, Groovy 및 JavaFX에서 너무 많은 작업을 수행하기 때문에 직관적으로 이해됩니다. 뷰와 컨트롤러 사이의 "매직"연결은 모두 일반적입니다. 방법의 이름을 잘 지정하는 것이 중요합니다.

보기에서 버튼 또는 다른 위젯에 onClick 메서드를 추가합니다.

    android:clickable="true"
    android:onClick="onButtonClickCancel"

그런 다음 클래스에서 메서드를 처리합니다.

public void onButtonClickCancel(View view) {
    Toast.makeText(this, "Cancel pressed", Toast.LENGTH_LONG).show();
}

다시 말하지만, 방법의 이름을 명확하게 지정하십시오. 어쨌든해야 할 일이 있으면 유지 관리가 두 번째 특성이됩니다.

한 가지 큰 장점은 이제 메서드에 대한 단위 테스트를 작성할 수 있다는 것입니다. 옵션 1은이를 수행 할 수 있지만 2와 3은 더 어렵습니다.


1
나는 약간의 와플을하고 옵션 2의 변형 인 다섯 번째 옵션 (아니요, Bruce Willis :)을 제안 할 것입니다. 클릭을 처리하기 위해 Model-View-Presenter 프레임 워크에서 Presenter 클래스를 사용합니다. 자동화 된 테스트를 훨씬 쉽게 만듭니다. : 더 나은 정보는이 링크를 확인 codelabs.developers.google.com/codelabs/android-testing/...
스티브 겔만

4

가장 많이 사용되는 방법은 익명 선언입니다.

    Button send = (Button) findViewById(R.id.buttonSend);
    send.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // handle click
        }
    });

또한 View.OnClickListener 객체를 생성하고 나중에 버튼으로 설정할 수 있지만, 예를 들어 여전히 onClick 메서드를 재정의해야합니다.

View.OnClickListener listener = new View.OnClickListener(){
     @Override
        public void onClick(View v) {
            // handle click
        }
}   
Button send = (Button) findViewById(R.id.buttonSend);
send.setOnClickListener(listener);

활동이 OnClickListener 인터페이스를 구현할 때 활동 수준에서 onClick (View v) 메서드를 재정의해야합니다. 그런 다음이 액티비티를 버튼에 대한 리스너로 지정할 수 있습니다. 이미 인터페이스를 구현하고 onClick () 메서드를 재정의하기 때문입니다.

public class MyActivity extends Activity implements View.OnClickListener{


    @Override
    public void onClick(View v) {
        // handle click
    }


    @Override
    public void onCreate(Bundle b) {
        Button send = (Button) findViewById(R.id.buttonSend);
        send.setOnClickListener(this);
    }

}

(imho) 여러 버튼에 동일한 핸들러가있을 때 사용되는 4 번째 접근 방식으로 액티비티 클래스에서 하나의 메서드를 선언하고이 메서드를 xml 레이아웃의 여러 버튼에 할당 할 수 있습니다. 또한 하나의 버튼에 대해 하나의 메서드를 생성 할 수 있습니다. 활동 클래스 내부에 핸들러를 선언하는 것을 선호합니다.


1

옵션 1과 2는 코드를 복잡하게 만드는 내부 클래스를 사용하는 것입니다. 옵션 2는 모든 버튼에 대해 하나의 리스너가 있기 때문에 다소 지저분합니다. 버튼 수가 적어도 괜찮습니다. 옵션 4의 경우 xml 및 Java 코드로 돌아가서 네 번째로 돌아 가야하므로 디버깅하기가 더 어려울 것이라고 생각합니다. 저는 개인적으로 여러 버튼 클릭을 처리해야 할 때 옵션 3을 사용합니다.


1

내 샘플, Android 스튜디오 2.1에서 테스트 됨

XML 레이아웃에서 버튼 정의

<Button
    android:id="@+id/btn1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

자바 맥동 감지

Button clickButton = (Button) findViewById(R.id.btn1);
if (clickButton != null) {
    clickButton.setOnClickListener( new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            /***Do what you want with the click here***/
        }
    });
}

1

ASP 질문 2에서 언급 한 것을 더 쉽게 만들기 위해 이와 같은 람다 메서드를 사용하여 변수 메모리를 절약하고 뷰 클래스에서 위아래로 탐색하지 않도록 할 수 있습니다.

//method 1
findViewById(R.id.buttonSend).setOnClickListener(v -> {
          // handle click
});

그러나 클릭 이벤트를 메서드에서 한 번에 버튼에 적용하려면.

@D의 질문 3을 사용할 수 있습니다. 트란 대답. 그러나 뷰 클래스를 View.OnClickListener.

다른 질문 # 3을 적절하게 사용하기 위해


1
이것은 메서드 참조 IMO와 결합 된 현대적인 답변으로 간주되어야합니다. 다른 답변의 대부분은 Android에서 Java8 이전 코드라는 사실을 밝히지 않습니다.
Ryan The Leach

0

질문 # 1-보기 클릭을 처리하는 유일한 방법입니다.

Question # 2-
Option # 1 / Option # 4 - Option # 1과 Option # 4 사이에는 큰 차이가 없습니다. 내가 보는 유일한 차이점은 하나의 경우 활동에서 OnClickListener를 구현하는 반면 다른 경우에는 익명 구현이 있다는 것입니다.

옵션 # 2-이 방법에서는 익명 클래스가 생성됩니다. 이 방법은 버튼이 여러 개인 경우 여러 번 수행해야하므로 약간 번거 롭습니다. 익명 클래스의 경우 메모리 누수 처리에주의해야합니다.

옵션 # 3-하지만 이것은 쉬운 방법입니다. 일반적으로 프로그래머는 작성하기 전까지는 어떤 방법도 사용하지 않기 때문에이 방법은 널리 사용되지 않습니다. 대부분 사람들이 옵션 # 4를 사용하는 것을 볼 수 있습니다. 코드 측면에서 더 깨끗하기 때문입니다.


안녕하세요 Gaurav, 답변 해 주셔서 감사합니다. 그러나 여기서 의미하는 바를 명확히 해주시겠습니까? 익명 클래스의 경우 메모리 누수 처리에주의해야합니다. 여기에 메모리 누수가 어떻게 발생합니까?
Budda 2013

앱의 수명 동안 여러 번 호출 될 수있는 메서드 내부에 익명 클래스를 만드는 경우 한 클래스의 여러 인스턴스가 생성되지 않고 인스턴스를 포함한 여러 클래스가 생성됩니다. 일반 내부 클래스를 사용하고 리스너를 인스턴스 필드로 인스턴스화하여이를 방지 할 수 있습니다. 생성자 인수를 통해 리스너 상태를 인식하도록하여 다른 리스너 클래스를 줄이십시오. 일반 내부 클래스는 사용자 지정 생성자 및 기타 메서드의 이점을 제공합니다.
Risadinha

0

다른 MVVM 프레임 워크를 사용하는 사람들에게이 프로세스를 매우 친숙하게 만들 수있는 다양한 라이브러리 형태의 옵션도 있습니다.

https://developer.android.com/topic/libraries/data-binding/

다음과 같이 버튼을 바인딩 할 수있는 공식 라이브러리의 예를 보여줍니다.

<Button
    android:text="Start second activity"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:onClick="@{() -> presenter.showList()}"
/>

0

1 단계 : XML 파일 생성 :

<?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:orientation="vertical">

    <Button
        android:id="@+id/btnClickEvent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me" />
</LinearLayout>

2 단계 : MainActivity 생성 :

package com.scancode.acutesoft.telephonymanagerapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity implements View.OnClickListener {

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

        btnClickEvent = (Button) findViewById(R.id.btnClickEvent);
        btnClickEvent.setOnClickListener(MainActivity.this);

    }

    @Override
    public void onClick(View v) {
        //Your Logic
    }
}

해피 코딩!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.