android : onClick XML 속성이 setOnClickListener와 정확히 어떻게 다릅니 까?
나는 당신이 onClick
두 가지 방법으로 버튼에 핸들러를 할당 할 수 있다는 것을 읽었습니다 .
android:onClick
서명과 함께 공용 메소드의 이름을 사용하는 XML 속성 void name(View v)
을 사용하거나 인터페이스 setOnClickListener
를 구현하는 오브젝트를 전달하는 메소드 를 사용하십시오 OnClickListener
. 후자는 종종 개인적으로 내가 싫어하는 (개인 취향) 또는를 구현하는 내부 클래스를 정의하는 익명 클래스가 필요합니다 OnClickListener
.
XML 속성을 사용하면 클래스 대신 메서드를 정의하면되므로 XML 레이아웃이 아닌 코드를 통해 동일한 작업을 수행 할 수 있는지 궁금합니다.
아니요, 코드로는 불가능합니다. Android OnClickListener
는 android:onClick="someMethod"
속성 을 정의 할 때 사용자를 대신 하여 구현 합니다.
이 두 코드 스 니펫은 동일하며 두 가지 다른 방식으로 구현됩니다.
코드 구현
Button btn = (Button) findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myFancyMethod(v);
}
});
// some more code
public void myFancyMethod(View v) {
// does something very interesting
}
위의 코드 구현은입니다 OnClickListener
. 그리고 이것은 XML 구현입니다.
XML 구현
<?xml version="1.0" encoding="utf-8"?>
<!-- layout elements -->
<Button android:id="@+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!"
android:onClick="myFancyMethod" />
<!-- even more layout elements -->
백그라운드에서 Android는 Java 코드 외에 다른 방법으로 click 이벤트에서 메소드를 호출합니다.
위의 XML을 사용하면 Android는 현재 활동에서만 onClick
메소드를 찾습니다 myFancyMethod()
. 프래그먼트를 사용하여 XML을 추가하더라도 Android는 XML을 추가하는 데 사용되는 프래그먼트 파일 에서 onClick
메소드를 찾지 않으므로 .java
프래그먼트를 사용하는 경우 기억해야합니다.
또 다른 중요한 점을 발견했습니다. 익명의 방법을 선호하지 않는다고 언급했습니다 . 익명 클래스 를 좋아하지 않는다고 말하려고했습니다 .
최고의 답변을 보았을 때 내 문제가 멋진 메소드에 매개 변수 (View v)를 넣지 않았다는 것을 깨달았습니다.
public void myFancyMethod(View v) {}
XML에서 액세스하려고 할 때
android:onClick="myFancyMethod"/>
누군가에게 도움이되기를 바랍니다.
android:onClick
는 API 수준 4 이상을위한 것이므로 <1.6을 타겟팅하는 경우 사용할 수 없습니다.
메소드를 공개하는 것을 잊었는지 확인하십시오!
android:onClick
속성을 지정 하면 Button
인스턴스가 setOnClickListener
내부적으로 호출 됩니다. 따라서 아무런 차이가 없습니다.
명확한 이해 onClick
를 위해 프레임 워크가 XML 속성을 처리 하는 방법을 살펴 보겠습니다 .
배치 파일이 팽창되면 여기에 지정된 모든 뷰가 인스턴스화됩니다. 이 경우 Button
인스턴스는 public Button (Context context, AttributeSet attrs, int defStyle)
생성자를 사용하여 생성됩니다. XML 태그의 모든 속성은 자원 번들에서 읽고 AttributeSet
생성자 로 전달됩니다 .
Button
클래스는 생성자를 호출 View
하는 클래스 에서 상속 View
되며을 통해 클릭 콜백 핸들러를 설정합니다 setOnClickListener
.
attrs.xml에 정의 된 onClick 속성은 View.java 에서로 참조됩니다 R.styleable.View_onClick
.
다음은 그 자체 View.java
로 전화 setOnClickListener
하여 대부분의 작업을 수행 하는 코드입니다 .
case R.styleable.View_onClick:
if (context.isRestricted()) {
throw new IllegalStateException("The android:onClick attribute cannot "
+ "be used within a restricted context");
}
final String handlerName = a.getString(attr);
if (handlerName != null) {
setOnClickListener(new OnClickListener() {
private Method mHandler;
public void onClick(View v) {
if (mHandler == null) {
try {
mHandler = getContext().getClass().getMethod(handlerName,
View.class);
} catch (NoSuchMethodException e) {
int id = getId();
String idText = id == NO_ID ? "" : " with id '"
+ getContext().getResources().getResourceEntryName(
id) + "'";
throw new IllegalStateException("Could not find a method " +
handlerName + "(View) in the activity "
+ getContext().getClass() + " for onClick handler"
+ " on view " + View.this.getClass() + idText, e);
}
}
try {
mHandler.invoke(getContext(), View.this);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not execute non "
+ "public method of the activity", e);
} catch (InvocationTargetException e) {
throw new IllegalStateException("Could not execute "
+ "method of the activity", e);
}
}
});
}
break;
보시다시피, setOnClickListener
코드에서와 같이 콜백을 등록하기 위해 호출됩니다. 단지 Java Reflection
우리의 활동에 정의 된 콜백 메소드를 호출하는 데 사용 한다는 점만 다릅니다 .
다른 답변에서 언급 된 문제의 이유는 다음과 같습니다.
- 콜백 방법은 공개한다 : 이후
Java Class getMethod
를 검색 지정자 공용 액세스 사용 만 기능한다. 그렇지 않으면IllegalAccessException
예외 를 처리 할 준비가됩니다 . - Fragment에서 onClick과 함께 Button을 사용하는 동안 콜백은 Activity에서 정의되어야합니다 .
getContext().getClass().getMethod()
call은 메소드 검색을 현재 컨텍스트 (Fragment의 경우 Activity)로 제한합니다. 따라서 메소드는 Fragment 클래스가 아닌 Activity 클래스 내에서 검색됩니다. - 콜백 방법은보기 매개 변수를 받아 들여야한다 가입일 :
Java Class getMethod
받아들이는 방법에 대한 검색View.class
매개 변수로합니다.
onClick XML 기능을 사용하려면 해당 메소드에 하나의 매개 변수가 있어야하며이 매개 변수의 유형은 XML 오브젝트와 일치해야합니다.
예를 들어, 버튼 은 이름 문자열을 통해 메소드에 연결 android:onClick="MyFancyMethod"
되지만 메소드 선언에는 다음이 표시되어야합니다....MyFancyMethod(View v) {...
이 기능을 메뉴 항목 에 추가하려고 하면 XML 파일에 정확히 동일한 구문이 사용되지만 메소드는 다음과 같이 선언됩니다....MyFancyMethod(MenuItem mi) {...
여기에 매우 좋은 답변이 있지만 한 줄을 추가하고 싶습니다.
에서 android:onclick
XML에서, 안드로이드는 사용하는 자바 반사를 이 처리하는 장면 뒤에.
그리고 여기에 설명 된 바와 같이, 반사는 항상 성능이 저하. (특히 Dhalvik VM에서). 등록 onClickListener
하는 것이 더 좋은 방법입니다.
클릭 리스너를 설정하는 다른 방법은 XML을 사용하는 것입니다. 태그에 android : onClick 속성을 추가하십시오.
가능할 때마다 익명 Java 클래스에서 xml 속성“onClick”을 사용하는 것이 좋습니다.
우선 코드의 차이점을 살펴 보겠습니다.
XML 속성 / onClick 속성
XML 부분
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:onClick="showToast"/>
자바 부분
public void showToast(View v) {
//Add some logic
}
익명의 Java 클래스 / setOnClickListener
XML 부분
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
자바 부분
findViewById(R.id.button1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
//Add some logic
}
});
익명 Java 클래스에 비해 XML 속성을 사용하면 다음과 같은 이점이 있습니다.
- Anonymous Java 클래스를 사용하면 항상 요소의 id를 지정해야하지만 XML 속성으로 id를 생략 할 수 있습니다.
- Anonymous Java 클래스를 사용하면 뷰 내부의 요소 (findViewById 부분)를 적극적으로 검색해야하지만 XML 속성을 사용하면 Android 가이를 수행합니다.
- 우리가 볼 수 있듯이 익명 Java 클래스에는 최소한 5 줄의 코드가 필요하지만 XML 속성을 사용하면 3 줄의 코드로 충분합니다.
- Anonymous Java 클래스를 사용하면 메소드의 이름을 "onClick"으로 지정해야하지만 XML 속성을 사용하면 원하는 이름을 추가 할 수 있으므로 코드의 가독성에 크게 도움이됩니다.
- API 레벨 4 릴리스 중에 Google에서 Xml "onClick"속성을 추가했습니다. 이는 좀 더 현대적인 구문이며 현대적인 구문이 거의 항상 더 좋습니다.
물론 Xml 속성을 사용하는 것이 항상 가능한 것은 아닙니다. 여기에 선택하지 않은 이유는 다음과 같습니다.
- 우리가 조각으로 작업하는 경우. onClick 속성은 액티비티에만 추가 할 수 있으므로 프래그먼트가 있으면 익명 클래스를 사용해야합니다.
- onClick 리스너를 별도의 클래스로 옮기고 싶다면 (매우 복잡하거나 응용 프로그램의 다른 부분에서 재사용하려는 경우) xml 속성을 사용하고 싶지 않습니다. 어느 한 쪽.
Add Button in xml and give onclick attribute name that is the name of Method.
<!--xml --!>
<Button
android:id="@+id/btn_register"
android:layout_margin="1dp"
android:onClick="addNumber"
android:text="Add"
/>
Button btnAdd = (Button) findViewById(R.id.mybutton); btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addNumber(v);
}
});
Private void addNumber(View v){
//Logic implement
switch (v.getId()) {
case R.id.btnAdd :
break;
default:
break;
}}
Java 8에서는 메소드 참조 를 사용 하여 원하는 것을 얻을 수 있습니다.
이것이 onClick
단추 의 이벤트 핸들러라고 가정하십시오 .
private void onMyButtonClicked(View v) {
if (v.getId() == R.id.myButton) {
// Do something when myButton was clicked
}
}
그런 다음 이와 같은 호출 onMyButtonClicked
에서 인스턴스 메소드 참조 를 전달 합니다 setOnClickListener()
.
Button myButton = (Button) findViewById(R.id.myButton);
myButton.setOnClickListener(this::onMyButtonClicked);
이렇게하면 익명 클래스를 명시 적으로 정의하지 않아도됩니다. 그러나 Java 8의 Method Reference는 실제로 구문 설탕이라는 것을 강조해야합니다. 실제로 람다 식처럼 익명 클래스의 인스턴스를 만듭니다. 따라서 람다 식 스타일의 이벤트 처리기가 이벤트 처리기 등록을 취소 할 때 적용되는 것과 비슷한주의가 필요합니다. 이 기사 는 정말 좋은 설명합니다.
추신. Android에서 Java 8 언어 기능을 실제로 어떻게 사용할 수 있는지 궁금한 사람들에게는 retrolambda 라이브러리 가 제공 합니다.
XML 속성을 사용하면 클래스 대신 메서드를 정의하면되므로 XML 레이아웃이 아닌 코드를 통해 동일한 작업을 수행 할 수 있는지 궁금합니다.
예, 당신은 당신을 만들 fragment
거나 activity
구현할 수 있습니다View.OnClickListener
코드에서 새 뷰 객체를 초기화하면 간단히 할 수 있습니다. mView.setOnClickListener(this);
그러면 코드의 모든보기 객체가 자동으로 설정 onClick(View v)
되어 귀하 fragment
또는 activity
기타가 가지고 있는 메소드 를 사용합니다 .
onClick
메소드 를 호출 한 뷰를 구별하기 위해 메소드에서 switch 문을 사용할 수 있습니다 v.getId()
.
이 답변은 "코드를 통해 불가능합니다"라는 답변과 다릅니다.
Ruivo의 답변을 지원합니다. 예, Android의 XML onclick에서 사용할 수 있도록 메소드를 "public"으로 선언해야합니다. API 레벨 8 (minSdk ...)에서 16 (targetSdk ...)까지 앱 타겟팅을 개발 중입니다.
내 방법을 개인으로 선언하고 오류가 발생하여 공용으로 작동한다고 선언했습니다.
이처럼 클릭 이벤트를 추가하고 싶다고 가정 해보십시오. main.xml
<Button
android:id="@+id/btn_register"
android:layout_margin="1dp"
android:layout_marginLeft="3dp"
android:layout_marginTop="10dp"
android:layout_weight="2"
android:onClick="register"
android:text="Register"
android:textColor="#000000"/>
Java 파일에서는이 메소드와 같은 메소드를 작성해야합니다.
public void register(View view) {
}
하지만, 조심 android:onClick
XML 핸들을 클릭 할 수있는 편리한 방법이 될 것 같다의 setOnClickListener
구현을 추가하는 것보다 추가로 뭔가를 onClickListener
. 실제로 view 속성 clickable
을 true로 설정했습니다.
전화 생성자에 따르면 대부분의 Android 구현에서는 문제가되지 않지만 버튼은 항상 기본적으로 clickable = true로 설정되지만 일부 전화 모델의 다른 생성자는 Button이 아닌 뷰에서 기본 clickable = false를 가질 수 있습니다.
따라서 XML을 설정하는 것만으로는 충분하지 않으며 항상 android:clickable="true"
버튼이 아닌 버튼 을 추가해야한다고 생각해야 하며 기본값이 clickable = true 인 장치가 있고이 XML 속성을 한 번이라도 잊어 버린 경우 눈치 채지 못할 것입니다 런타임에 문제가 있지만 고객의 손에있을 때 시장에 대한 피드백을 얻을 것입니다!
또한 proguard가 XML 속성 및 클래스 메서드를 난독 화하고 이름을 바꾸는 방법에 대해 확신 할 수 없으므로 언젠가는 버그가 발생하지 않도록 100 % 안전하지 않습니다.
따라서 어려움을 겪고 싶지 않고 생각하지 않으려면 setOnClickListener
ButterKnife와 같은 라이브러리를 주석과 함께 사용하는 것이 좋습니다@OnClick(R.id.button)
이 코드를 XML 파일로 작성하고 있습니다 ...
<Button
android:id="@+id/btn_register"
android:layout_margin="1dp"
android:layout_marginLeft="3dp"
android:layout_marginTop="10dp"
android:layout_weight="2"
android:onClick="register"
android:text="Register"
android:textColor="#000000"/>
그리고이 코드를 조각으로 작성하십시오 ...
public void register(View view) {
}
이를 수행하는 가장 좋은 방법은 다음 코드를 사용하는 것입니다.
Button button = (Button)findViewById(R.id.btn_register);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do your fancy method
}
});
'Programming' 카테고리의 다른 글
Mockito가 여러 번 호출되는 메소드의 인수를 캡처 할 수 있습니까? (0) | 2020.02.22 |
---|---|
Go에서 두 조각을 연결 (0) | 2020.02.22 |
SQL Server에서 INSERT INTO로 데이터 내보내기 (0) | 2020.02.22 |
계산량이 많은 경우 Fortran을 C보다 최적화하기가 더 쉽습니까? (0) | 2020.02.22 |
API 레벨 Android Studio 변경 (0) | 2020.02.22 |