Указание атрибута android:onClick
приводит к тому, что Button
экземпляр вызывает setOnClickListener
внутри.Следовательно, нет абсолютно никакой разницы.
Чтобы иметь четкое понимание, давайте посмотрим, как атрибут XML onClick
обрабатывается платформой.
Когда файл макета раздувается, все представления, указанные вэто экземпляры.В этом конкретном случае экземпляр 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. - Метод обратного вызова должен принимать параметр просмотра : так как
Java Class getMethod
ищет метод, который принимает View.class
какпараметр.