指定android:onClick
属性会导致Button
实例在内部调用setOnClickListener
。因此,没有任何区别。
为了更清楚地理解,让我们看看框架如何处理XML onClick
属性。
当布局文件被展开时,其中指定的所有视图都将被实例化。在这种特定情况下,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
来调用我们 Activity 中定义的回调方法。
以下是其他答案中提到的问题的原因:
- 回调方法应该是公共的:由于使用了
Java Class getMethod
,只有具有公共访问修饰符的函数才会被搜索。否则,请准备好处理 IllegalAccessException
异常。
- 在 Fragment 中使用 Button 与 onClick 时,回调应该在 Activity 中定义:
getContext().getClass().getMethod()
调用将方法搜索限制为当前上下文,即在 Fragment 的情况下为 Activity。因此,该方法在 Activity 类中而不是 Fragment 类中进行搜索。
- 回调方法应该接受 View 参数:由于
Java Class getMethod
搜索接受 View.class
参数的方法。
onClick
属性方法。这归功于参数View v
。您只需检查if(v == findViewById(R.id.button1))
等即可。 - CodyBugsteinv.getId() == R.id.button1
,因为您不必寻找实际控件并进行比较。您可以使用switch
代替很多if
语句。 - Sami Kuhmonen