指定android:onClick属性会导致Button实例在setOnClickListener内部调用。因此,绝对没有区别。
为了清楚理解,让我们看看onClick框架如何处理XML 属性。
放大布局文件时,将实例化其中指定的所有视图。在这种特定情况下,Button实例是使用public Button (Context context, AttributeSet attrs, int defStyle)构造函数创建的。从资源束中读取XML标记中的所有属性,并将其传递AttributeSet给构造函数。
Buttonclass从Viewclass 继承而来,导致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调用我们的Activity中定义的回调方法。
这是其他答案中提到的问题的原因: 
- 回调方法应为public:由于Java Class getMethod使用了回调方法,因此仅搜索具有公共访问说明符的函数。否则准备处理IllegalAccessException异常。
- 在Fragment中将Button与onClick结合使用时,应在Activity中定义回调:getContext().getClass().getMethod()call会将方法搜索限制为当前上下文,在Fragment的情况下为Activity。因此,方法是在Activity类而不是Fragment类中搜索的。
- 回调方法应接受View parameter:因为Java Class getMethod搜索接受View.class作为参数的方法。