사실 이거는 내가 진행하고 있는 공부와는 별개로 내가 공부하다가 궁금해서 공부하게 된 내용이다.
책에 있는 예제를 따라 할 때마다 어떤 거는 익명 객체를 생성하고 어떤 거는 xml과 연동하고 있다.
그래서 나는 상황에 따라 어떤 버튼 클릭 이벤트 처리 방법을 쓰는지 궁금하게 됐다.
그럼 각자 버튼 클릭 이벤트를 처리하는 방식을 어떤 상황에 맞춰서 사용하는지 알아보자.
1. 익명 클래스를 생성하여 이벤트 리스너로 사용할때
ex)
final TextView textView1 = (TextView) findViewById(R.id.textView1);
Button buttonGreen = (Button) findViewById(R.id.buttonGreen) ;
buttonGreen.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View view) {
textView1.setText("Green") ;
textView1.setBackgroundColor(Color.rgb(0, 255, 0));
}
}) ;
해당 방식과 같은 방식을 사용할 때는 아래와 같을 때 추천한다.
1-1. 버튼의 개수가 적거나 버튼들 간의 연관성이 적을 때
이유 : 버튼이 많으면 많은 익명 객체를 생성해야 하는 문제가 생긴다.
그래서 연관된 게 많으면 그만큼 코드의 양이 늘어나기도 하고 비슷한 기능을 하는 버튼이더라도
서로 아예 상관없는 것으로 인식될 가능성 있기 때문.
1-2. 이벤트 핸들러 함수 내에서 익명 클래스 외부의 변수를
참조하지 않는 경우
이유 : 익명 클래스 외부에 있는 변수를 참조하려면 외부 변수는 항상 final로 선언이 되어야 한다
(안 그러면 에러 나기 때문)
그래서 외부 변수 참조를 안할 때 사용
1-3. 간단한 버튼 클릭 이벤트를 할때
이유 : 1번과 2번 경우가 아닌 경우는 보통 이벤트가 작은 기능을 할 때이기 때문
2. 익명 클래스 객체를 먼저 만들어 놓고 그 객체를 모든 버튼의 이벤트 리스너로 사용할 때
2번과 같은 경우는 어떤 경우인지 일단 소스를 통해서 보여주겠다.
Button.OnClickListener onClickListener = new Button.OnClickListener() {
@Override
public void onClick(View view) {
TextView textView1 = (TextView) findViewById(R.id.textView1);
switch (view.getId()) {
case R.id.buttonRed :
textView1.setText("Red") ;
textView1.setBackgroundColor(Color.rgb(255, 0, 0));
break ;
case R.id.buttonGreen :
textView1.setText("Green") ;
textView1.setBackgroundColor(Color.rgb(0, 255, 0));
break ;
case R.id.buttonBlue :
textView1.setText("Blue") ;
textView1.setBackgroundColor(Color.rgb(0, 0, 255));
break ;
}
}
} ;
Button buttonRed = (Button) findViewById(R.id.buttonRed) ;
buttonRed.setOnClickListener(onClickListener) ;
위 소스를 보면 아니 왜 객체를 생성하는데 익명 클래스인 것이냐 라는 생각이 들 수가 있다.
(왜냐 내가 그런 생각을 했기 때문)
위 방식은 익명 클래스인 이유는 객체를 생성하는 게 아니라 Button.OnClickListener의 기능을 상속받는
새로운 클래스를 만들지 않고 익명으로 생성해서 객체를 생성하기 때문이다.
무튼 그래서 위와 같은 방식은 어떤 때 사용하는지 알아보자.
2-1. 버튼이 여러 개 존재하고 버튼들 간의 연관성이 많을 때
이유 : 익명 클래스 방식으로 클릭 이벤트 핸들러 객체를 생성 했으니 여러번 사용할수 있기 때문이다.
2-2. 이벤트 핸들러 함수 내에서 익명클래스 외부의 변수를
참조하지 않을 때
이유 : 이것도 마찬가지로 결국에는 익명 클래스를 생성하는 것이기 때문에 외부 변수를 참조할 땐 final을 사용해야 한다.
2-3. 추후 같은 기능으로 하는 버튼을 사용할 때
이유 : 이것도 아마 2-1번과 같은 맥락일 거 같다.
3. 3. Button.OnClickListener를 상속받는 클래스 생성하여 해당 클래스로 객체 생성해서
그 클래스로 이벤트 리스너 등록하기
ex)
class BtnOnClickListener implements Button.OnClickListener {
@Override
public void onClick(View view) {
TextView textView1 = (TextView) findViewById(R.id.textView1);
switch (view.getId()) {
case R.id.buttonRed :
textView1.setText("Red") ;
textView1.setBackgroundColor(Color.rgb(255, 0, 0));
break ;
case R.id.buttonGreen :
textView1.setText("Green") ;
textView1.setBackgroundColor(Color.rgb(0, 255, 0));
break ;
case R.id.buttonBlue :
textView1.setText("Blue") ;
textView1.setBackgroundColor(Color.rgb(0, 0, 255));
break ;
}
}
}
// BtnOnClickListener의 객체 생성.
BtnOnClickListener onClickListener = new BtnOnClickListener() ;
// 각 Button의 이벤트 리스너로 onClickListener 지정.
Button buttonRed = (Button) findViewById(R.id.buttonRed) ;
buttonRed.setOnClickListener(onClickListener) ;
이번 방식이야 말로 익명 객체가 아닌 것이다.
위와 같은 방식으로 사용할 때는
3-1. 인터페이스를 상속하여 만들어서 코드의 가독성을 높이고 싶을 때
이유 : 따로 클래스를 만드니 가독성 올라감
3-2. 추후 같은 기능으로 버튼을 추가하려고 할 때
이유: 클래스 만드니 코드 재사용 안 함
4. Activity에서 Button.OncliclListener implements 해서 사용할 때
ex)
public class MainActivity extends AppCompatActivity implements Button.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
// ... 코드 계속.
// 각 Button의 이벤트 리스너로 this(MainActivity) 지정.
Button buttonRed = (Button) findViewById(R.id.buttonRed) ;
buttonRed.setOnClickListener(this) ;
Button buttonGreen = (Button) findViewById(R.id.buttonGreen) ;
buttonGreen.setOnClickListener(this) ;
Button buttonBlue = (Button) findViewById(R.id.buttonBlue) ;
buttonBlue.setOnClickListener(this) ;
}
// Button.OnclickListener를 implements하므로 onClick() 함수를 오버라이딩.
@Override
public void onClick(View view) {
TextView textView1 = (TextView) findViewById(R.id.textView1);
switch (view.getId()) {
case R.id.buttonRed :
textView1.setText("Red") ;
textView1.setBackgroundColor(Color.rgb(255, 0, 0));
break ;
case R.id.buttonGreen :
textView1.setText("Green") ;
textView1.setBackgroundColor(Color.rgb(0, 255, 0));
break ;
case R.id.buttonBlue :
textView1.setText("Blue") ;
textView1.setBackgroundColor(Color.rgb(0, 0, 255));
break ;
}
}
}
위 코드에서 보면 Activity에서 Button.OncliclListener를 implements 하기 때문에
buttonRed.setOnClickListener(this); 에 this 가 들어가는 것이다.
이 방식을 사용할 때는
4-1. 핸들러 함수에서 많은 수의 Activity멤버를 접근해야 할 경우
이유 : 핸들러가 많은 Activity를 접근해야 한다면 그 Activity마다 다르기 때문에 이와 같은 방식으로 해줘야 한다.
4-2. 액티비티 내부의 버튼들에 대한 클릭 이벤트를 한 곳에서 처리하고 싶은 경우
이유 : 하나의 Activity내에서 버튼 클릭 이벤트를 onClick()이라는 함수로 모을 수 있기 때문
4-3. 익명 클래스 또는 별도의 이벤트 리스너를 만들고 싶지 않은 경우
5. Layout에서 onclick 속성 이용하는 경우
ex)
xml
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/buttonBlue"
android:text="BLUE"
android:layout_weight="1"
android:onClick="onButtonClick" />
java
public void onButtonClick(View view) {
TextView textView1 = (TextView) findViewById(R.id.textView1);
switch (view.getId()) {
case R.id.buttonRed :
textView1.setText("Red") ;
textView1.setBackgroundColor(Color.rgb(255, 0, 0));
break ;
case R.id.buttonGreen :
textView1.setText("Green") ;
textView1.setBackgroundColor(Color.rgb(0, 255, 0));
break ;
case R.id.buttonBlue :
textView1.setText("Blue") ;
textView1.setBackgroundColor(Color.rgb(0, 0, 255));
break ;
}
}
이 방식을 사용을 최대한 지양해야 한다.
그 이유는 layout에서 이벤트 처리하게 되면 이벤트 처리를 하게 되는 java 코드와 역할 구분 모호해지고
클릭 이벤트 간의 관계 파악하기도 힘들기 때문이다.
그래도 이 방법을 사용하고 싶다면 아래와 같은 상황일 때 사용하기 바란다.
5-1. 버튼 개수 진짜 적을 때
5-2. 버튼의 테스트 코드 적을때
5-3. 이벤트 리스너를 별도로 작성하는 게 번거로울 때
5-4. 가장 직관적인 방법을 선호할 때
참조 블로그 : recipes4dev.tistory.com/55
'코딩일기 > android studio' 카테고리의 다른 글
안드로이드 독학 19일차 : 알림(Notification) (6) | 2021.04.09 |
---|---|
안드로이드 독학 18일차 : 커스텀 대화상자(Custom Dialog) (0) | 2021.04.08 |
안드로이드 독학 17일차 : DatePickerDialog & TimePickerDialog (2) | 2021.04.01 |
안드로이드 독학 16일차 : Dialog(대화상자) (2) | 2021.03.31 |
안드로이드 독학 16일차 : 팝업 메뉴(PopupMenu) (2) | 2021.03.31 |