从我所读到的,你可以用两种方式为按钮分配onClick处理程序。

使用android:onClick XML属性,你只是使用一个公共方法的名称与signaturevoid名称(View v)或通过使用setOnClickListener方法,你传递一个实现OnClickListener接口的对象。后者通常需要一个匿名类,我个人不喜欢(个人口味)或定义一个实现OnClickListener的内部类。

通过使用XML属性,你只需要定义一个方法而不是一个类 想知道同样的事情是否可以通过代码而不是在XML布局中完成。


当前回答

当我看到顶部的答案时,它让我意识到我的问题不是把参数(View v)放在花哨的方法上:

public void myFancyMethod(View v) {}

当试图从xml中访问它时,应该使用

android:onClick="myFancyMethod"/>

其他回答

指定android:onClick属性会导致Button实例在内部调用setOnClickListener。因此两者绝对没有区别。

为了更清楚地理解,让我们看看框架是如何处理XML onClick属性的。

当布局文件被膨胀时,其中指定的所有视图都会被实例化。在这个特定的情况下,Button实例是使用公共Button (Context Context, AttributeSet attrs, int defStyle)构造函数创建的。XML标记中的所有属性都是从资源包中读取的,并作为AttributeSet传递给构造函数。

Button类继承自View类,它导致View构造函数被调用,View构造函数通过setOnClickListener负责设置点击回调处理程序。

在attrs.xml中定义的onClick属性在View.java中被引用为r.s eleable . 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来调用Activity中定义的回调方法。

以下是其他回答中提到的问题的原因:

Callback method should be public : Since Java Class getMethod is used, only functions with public access specifier are searched for. Otherwise be ready to handle IllegalAccessException exception. While using Button with onClick in Fragment, the callback should be defined in Activity : getContext().getClass().getMethod() call restricts the method search to the current context, which is Activity in case of Fragment. Hence method is searched within Activity class and not Fragment class. Callback method should accept View parameter : Since Java Class getMethod searches for method which accepts View.class as parameter.

不,通过代码是不可能的。当你定义Android:onClick="someMethod"属性时,Android只是实现了OnClickListener。

这两个代码段是相等的,只是以两种不同的方式实现。

代码实现

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代码,在点击事件时调用你的方法。

注意,使用上面的XML, Android将只在当前Activity中寻找onClick方法myFancyMethod()。如果你正在使用片段,记住这一点很重要,因为即使你使用片段添加上面的XML, Android也不会在用于添加XML的片段的.java文件中查找onClick方法。

我注意到另一件重要的事情。你提到你不喜欢匿名方法。你的意思是说你不喜欢匿名课程。

小心,虽然android:onClick XML似乎是一个方便的方式来处理点击,setOnClickListener实现做一些额外的添加onClickListener。实际上,它把视图属性clickable设为true。

虽然这可能不是大多数Android实现的问题,根据手机构造函数,按钮总是默认为clickable = true,但在一些手机模型上的其他构造函数可能在非button视图上有默认clickable = false。

所以设置XML是不够的,你必须一直考虑在非按钮上添加android:clickable="true",如果你有一个默认为clickable= true的设备,你甚至忘记放置这个XML属性,你不会在运行时注意到这个问题,但会在市场上得到反馈,当它将在你的客户手中!

此外,我们永远无法确定proguard将如何混淆和重命名XML属性和类方法,所以不是100%安全,它们永远不会有任何错误。

因此,如果你不想有麻烦,也不想想它,最好使用setOnClickListener或ButterKnife这样的库,annotation @OnClick(R.id.button)

   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;
    }}

假设,你想添加这样的点击事件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) {
}