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

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

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


当前回答

指定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.

其他回答

在Java 8中,您可以使用Method Reference来实现您想要的功能。

假设这是按钮的onClick事件处理程序。

private void onMyButtonClicked(View v) {
    if (v.getId() == R.id.myButton) {
        // Do something when myButton was clicked
    }
}

然后,像这样在setOnClickListener()调用中传递onMyButtonClicked实例方法引用。

Button myButton = (Button) findViewById(R.id.myButton);
myButton.setOnClickListener(this::onMyButtonClicked);

这将允许您避免自己显式地定义匿名类。然而,我必须强调,Java 8的Method Reference实际上只是一个语法糖。它实际上为您创建了一个匿名类的实例(就像lambda表达式所做的那样),因此当您要取消事件处理程序的注册时,会应用lambda表达式风格的事件处理程序。这篇文章解释得很好。

PS.对于那些好奇我如何在Android中真正使用Java 8语言功能的人,这是retrolambda库的礼貌。

android:onClick是API级别4以上,所以如果你的目标< 1.6,那么你不能使用它。

为了让你的生活更简单,并避免setOnClicklistener()中的匿名类,实现一个视图。OnClicklistener接口如下:

公共类YourClass扩展了CommonActivity,实现了View。OnClickListener,……

这避免了:

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        yourMethod(v);
    }
});

并直接指向:

@Override
public void onClick(View v) {
  switch (v.getId()) {
    case R.id.your_view:
      yourMethod();
      break;
  }
}

通过使用XML属性,您只需要定义一个方法而不是 一个类,所以我想知道如果同样可以通过代码而不是在 XML布局。

是的,你可以让你的片段或活动实现视图。OnClickListener

当你在代码中初始化你的新视图对象时,你可以简单地做mView.setOnClickListener(this);

这将自动设置代码中的所有视图对象使用onClick(view v)方法,您的片段或活动等。

为了区分哪个视图调用了onClick方法,你可以在v.getId()方法上使用switch语句。

这个答案不同于“不,通过代码是不可能的”

我在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) {
}