指定android:onClick
属性会导致Button
实例在setOnClickListener
内部调用。因此,绝对没有区别。
为了清楚理解,让我们看看onClick
框架如何处理XML 属性。
放大布局文件时,将实例化其中指定的所有视图。在这种特定情况下,Button
实例是使用public Button (Context context, AttributeSet attrs, int defStyle)
构造函数创建的。从资源束中读取XML标记中的所有属性,并将其传递AttributeSet
给构造函数。
Button
class从View
class 继承而来,导致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
作为参数的方法。