Указание android:onClick
атрибута приводит к внутреннему Button
вызову экземпляра setOnClickListener
. Следовательно, нет абсолютно никакой разницы.
Чтобы иметь четкое понимание, давайте посмотрим, как onClick
атрибут XML обрабатывается платформой.
Когда файл макета раздувается, создаются все экземпляры, указанные в нем. В этом конкретном случае Button
экземпляр создается с помощью public Button (Context context, AttributeSet attrs, int defStyle)
конструктора. Все атрибуты в теге XML считываются из пакета ресурсов и передаются как AttributeSet
конструктору.
Button
Класс наследуется от View
класса, что приводит View
к вызову конструктора, который заботится о настройке обработчика обратного вызова click через setOnClickListener
.
Атрибут onClick , определенный в attrs.xml , называется в 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
для вызова метода обратного вызова, определенного в нашей Деятельности.
Вот причина проблем, упомянутых в других ответах:
- Метод обратного вызова должен быть общедоступным : поскольку
Java Class getMethod
он используется, ищутся только функции со спецификатором открытого доступа. В противном случае будьте готовы обработать IllegalAccessException
исключение.
- При использовании Button с onClick во Fragment, обратный вызов должен быть определен в Activity :
getContext().getClass().getMethod()
вызов ограничивает поиск метода текущим контекстом, которым является Activity в случае Fragment. Следовательно, метод ищется в классе Activity, а не в классе Fragment.
- Метод обратного вызова должен принимать параметр View : Так как
Java Class getMethod
ищет метод, который принимает в View.class
качестве параметра.