Programming

android : onClick XML 속성이 setOnClickListener와 정확히 어떻게 다릅니 까?

procodes 2020. 2. 22. 12:00
반응형

android : onClick XML 속성이 setOnClickListener와 정확히 어떻게 다릅니 까?


나는 당신이 onClick두 가지 방법으로 버튼에 핸들러를 할당 할 수 있다는 것을 읽었습니다 .

android:onClick서명과 함께 공용 메소드의 이름을 사용하는 XML 속성 void name(View v)을 사용하거나 인터페이스 setOnClickListener를 구현하는 오브젝트를 전달하는 메소드 를 사용하십시오 OnClickListener. 후자는 종종 개인적으로 내가 싫어하는 (개인 취향) 또는를 구현하는 내부 클래스를 정의하는 익명 클래스가 필요합니다 OnClickListener.

XML 속성을 사용하면 클래스 대신 메서드를 정의하면되므로 XML 레이아웃이 아닌 코드를 통해 동일한 작업을 수행 할 수 있는지 궁금합니다.


아니요, 코드로는 불가능합니다. Android OnClickListenerandroid: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:onclickXML에서, 안드로이드는 사용하는 자바 반사를 이 처리하는 장면 뒤에.

그리고 여기에 설명 된 바와 같이, 반사는 항상 성능이 저하. (특히 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:onClickXML 핸들을 클릭 할 수있는 편리한 방법이 될 것 같다의 setOnClickListener구현을 추가하는 것보다 추가로 뭔가를 onClickListener. 실제로 view 속성 clickable을 true로 설정했습니다.

전화 생성자에 따르면 대부분의 Android 구현에서는 문제가되지 않지만 버튼은 항상 기본적으로 clickable = true로 설정되지만 일부 전화 모델의 다른 생성자는 Button이 아닌 뷰에서 기본 clickable = false를 가질 수 있습니다.

따라서 XML을 설정하는 것만으로는 충분하지 않으며 항상 android:clickable="true"버튼이 아닌 버튼 을 추가해야한다고 생각해야 하며 기본값이 clickable = true 인 장치가 있고이 XML 속성을 한 번이라도 잊어 버린 경우 눈치 채지 못할 것입니다 런타임에 문제가 있지만 고객의 손에있을 때 시장에 대한 피드백을 얻을 것입니다!

또한 proguard가 XML 속성 및 클래스 메서드를 난독 화하고 이름을 바꾸는 방법에 대해 확신 할 수 없으므로 언젠가는 버그가 발생하지 않도록 100 % 안전하지 않습니다.

따라서 어려움을 겪고 싶지 않고 생각하지 않으려면 setOnClickListenerButterKnife와 같은 라이브러리를 주석과 함께 사용하는 것이 좋습니다@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
            }
        });

참고 URL : https://stackoverflow.com/questions/4153517/how-exactly-does-the-androidonclick-xml-attribute-differ-from-setonclicklistene



반응형