Как отличается атрибут android: onClick XML от setOnClickListener?
Из того, что я прочитал, вы можете назначить обработчик onClick
кнопке двумя способами.
Использование атрибута android:onClick
XML, в котором вы просто используете имя общедоступного метода с сигнатурой void name(View v)
или с помощью метода setOnClickListener
, где вы передаете объект, реализующий интерфейс OnClickListener
. Последнее часто требует анонимного класса, который лично мне не нравится (личный вкус) или определения внутреннего класса, который реализует OnClickListener
.
Используя атрибут XML, вам просто нужно определить метод вместо класса, чтобы я был
интересно, может ли это быть сделано через код, а не в XML-макете.
Ответы
Ответ 1
Нет, это невозможно с помощью кода. Android просто реализует OnClickListener
для вас, когда вы определяете атрибут android:onClick="someMethod"
.
Эти два фрагмента кода равны, просто реализованы двумя разными способами.
Внедрение кода
Button btn = (Button) findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myFancyMethod(v);
}
});
// some more code
public void myFancyMethod(View v) {
// does something very interesting
}
Выше представлена реализация кода OnClickListener
. И это реализация XML.
Внедрение XML
<?xml version="1.0" encoding="utf-8"?>
<!-- layout elements -->
<Button android:id="@+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!"
android:onClick="myFancyMethod" />
<!-- even more layout elements -->
В фоновом режиме Android делает не что иное, как код Java, вызывая ваш метод при событии клика.
Обратите внимание, что с помощью XML выше Android будет искать метод onClick
myFancyMethod()
только в текущей Activity. Это важно помнить, если вы используете фрагменты, так как даже если вы добавите XML выше, используя фрагмент, Android не будет искать метод onClick
в файле .java
фрагмента, используемого для добавления XML.
Еще одна важная вещь, которую я заметил. Вы упомянули, что не предпочитаете анонимные методы. Вы хотели сказать, что вам не нравятся анонимные классы.
Ответ 2
Когда я увидел верхний ответ, я понял, что моя проблема не в том, чтобы поместить параметр (View v) в причудливый метод:
public void myFancyMethod(View v) {}
При попытке получить доступ к нему из XML, следует использовать
android:onClick="myFancyMethod"/>
Надеюсь, что это помогает кому-то.
Ответ 3
android:onClick
для уровня API 4, и поэтому, если вы нацеливаете < 1.6, то вы не можете его использовать.
Ответ 4
Проверьте, не забыл ли вы опубликовать этот метод!
Ответ 5
Указание атрибута android:onClick
приводит к тому, что экземпляр Button
вызывает setOnClickListener
внутренне. Следовательно, нет никакой разницы.
Чтобы иметь ясное понимание, давайте посмотрим, как XML-атрибут onClick
обрабатывается каркасом.
Когда файл макета завышен, все Представленные в нем Представления создаются. В этом конкретном случае экземпляр Button
создается с помощью конструктора public Button (Context context, AttributeSet attrs, int defStyle)
. Все атрибуты в теге XML считываются из пакета ресурсов и передаются как AttributeSet
в конструктор.
Button
класс наследуется от класса View
, в результате которого вызывается конструктор View
, который заботится о настройке обработчика обратного вызова щелчка через 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
.
- При использовании кнопки с onClick in Fragment обратный вызов должен быть определен в Activity:
getContext().getClass().getMethod()
вызов ограничивает поиск метода текущим контекстом, который является Activity в случае Fragment. Следовательно, поиск метода выполняется в классе Activity, а не в классе Fragment.
- Метод обратного вызова должен принимать параметр View. Поскольку
Java Class getMethod
ищет метод, который принимает View.class
как параметр.
Ответ 6
Обратите внимание, что если вы хотите использовать функцию onClick XML, соответствующий метод должен иметь один параметр, тип которого должен соответствовать объекту XML.
Например, кнопка будет привязана к вашему методу через строку имени: android:onClick="MyFancyMethod"
, но объявление метода должно показать:
...MyFancyMethod(View v) {...
Если вы пытаетесь добавить эту функцию в элемент меню, она будет иметь тот же синтаксис в файле XML, но ваш метод будет объявлен как: ...MyFancyMethod(MenuItem mi) {...
Ответ 7
Здесь есть очень хорошие ответы, но я хочу добавить одну строку:
В android:onclick
в XML Android использует Java-отражение за сценой, чтобы справиться с этим.
И , как объясняется здесь, отражение всегда замедляет производительность. (особенно на Далвик В.М.). Регистрация onClickListener
- лучший способ.
Ответ 8
Другим способом установки ваших прослушивателей кликов будет использование XML. Просто добавьте android: атрибут onClick в свой тег.
Хорошей практикой является использование атрибута xml "onClick" над анонимным классом Java, когда это возможно.
Прежде всего, давайте рассмотрим разницу в коде:
атрибут атрибута XML/onClick
Часть XML
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:onClick="showToast"/>
Часть Java
public void showToast(View v) {
//Add some logic
}
Анонимный класс Java/setOnClickListener
Часть XML
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Часть Java
findViewById(R.id.button1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
//Add some logic
}
});
Вот преимущества использования атрибута XML над анонимным классом Java:
- С анонимным Java-классом мы всегда должны указывать идентификатор для нашего
элементов, но с идентификатором атрибута XML можно опустить.
- С анонимным Java-классом мы должны активно искать элемент
внутри части view (findViewById), но с атрибутом XML
Android делает это для нас.
- Анонимный класс Java требует не менее 5 строк кода, так как мы можем
см., но с атрибутом XML достаточно 3 строк кода.
- С анонимным классом Java мы должны назвать наш метод "onClick" ,
но с атрибутом XML мы можем добавить любое имя, которое мы хотим, которое будет
значительно помогают с читабельностью нашего кода.
- Атрибут Xml "onClick" был добавлен Google во время уровня API
4, что означает, что это немного более современный синтаксис и современный
синтаксис почти всегда лучше.
Конечно, не всегда можно использовать атрибут Xml, вот почему мы его не выбрали:
- Если мы работаем с фрагментами. атрибут onClick может быть добавлен только
к активности, поэтому, если у нас есть фрагмент, мы должны будем использовать
анонимный класс.
- Если мы хотим переместить прослушиватель onClick в отдельный класс
(возможно, если это очень сложно и/или мы хотели бы повторно использовать его в
различные части нашего приложения), то мы не хотели бы использовать
xml.
Ответ 9
Используя атрибут XML, вам просто нужно определить метод вместо класс, поэтому мне было интересно, можно ли сделать то же самое с помощью кода, а не в XML-макет.
Да, вы можете реализовать fragment
или activity
View.OnClickListener
и когда вы инициализируете свои новые объекты в коде, вы можете просто сделать mView.setOnClickListener(this);
и это автоматически устанавливает все объекты вида в коде, чтобы использовать метод onClick(View v)
, который имеет ваш fragment
или activity
и т.д.
чтобы отличить, какой вид вызвал метод onClick
, вы можете использовать оператор switch для метода v.getId()
.
Этот ответ отличается от того, который говорит "Нет, что невозможно с помощью кода"
Ответ 10
Add Button in xml and give onclick attribute name that is the name of Method.
<!--xml --!>
<Button
android:id="@+id/btn_register"
android:layout_margin="1dp"
android:onClick="addNumber"
android:text="Add"
/>
Button btnAdd = (Button) findViewById(R.id.mybutton); btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addNumber(v);
}
});
Private void addNumber(View v){
//Logic implement
switch (v.getId()) {
case R.id.btnAdd :
break;
default:
break;
}}
Ответ 11
С помощью Java 8 вы, вероятно, можете использовать Справочник по методу для достижения того, что вы хотите.
Предположим, что это ваш обработчик событий onClick
для кнопки.
private void onMyButtonClicked(View v) {
if (v.getId() == R.id.myButton) {
// Do something when myButton was clicked
}
}
Затем вы передаете ссылку метода экземпляра onMyButtonClicked
в вызове setOnClickListener()
, подобном этому.
Button myButton = (Button) findViewById(R.id.myButton);
myButton.setOnClickListener(this::onMyButtonClicked);
Это позволит вам избежать явного определения анонимного класса самостоятельно. Однако я должен подчеркнуть, что Java 8 Method Reference на самом деле является просто синтаксическим сахаром. Он фактически создает для вас экземпляр анонимного класса (так же, как и выражение лямбда), поэтому аналогичная осторожность, поскольку обработчик событий типа lambda-expression-style применяется, когда вы приходите к незарегистрированию вашего обработчика событий. Эта статья объясняет, что это действительно приятно.
PS. Для тех, кто интересуется, как я могу использовать Java 8-языковую функцию в Android, это любезно предоставлено retrolambda.
Ответ 12
Поддержка ответа Ruivo, да, вы должны объявить метод "общедоступным", чтобы иметь возможность использовать в Android XML onclick. Я разрабатываю таргетинг приложений с уровня API 8 (minSdk...) до 16 (targetSdk...).
Я объявлял свой метод как закрытый, и он вызывал ошибку, просто объявляя его общедоступным.
Ответ 13
Предположим, вы хотите добавить событие click, например, main.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"/>
В java файле вам нужно написать такой метод, как этот метод.
public void register(View view) {
}
Ответ 14
Будьте осторожны, хотя android:onClick
XML, по-видимому, является удобным способом обработки щелчка, реализация setOnClickListener
делает что-то дополнительное, чем добавление onClickListener
. В самом деле, он поместил свойство view clickable
в значение true.
Хотя это может и не быть проблемой для большинства реализаций Android, по словам конструктора телефона, кнопка всегда по умолчанию имеет значение clickable = true, но другие конструкторы на какой-либо модели телефона могут иметь по умолчанию clickable = false для просмотров без кнопок.
Таким образом, для установки XML недостаточно, вы должны постоянно думать о том, чтобы добавить android:clickable="true"
в не-кнопку, и если у вас есть устройство, в котором значение по умолчанию - clickable = true, и вы даже один раз забываете поместить этот атрибут XML, вы не заметите проблему во время работы, но получите обратную связь на рынке, когда она будет в руках ваших клиентов!
Кроме того, мы никогда не можем быть уверены в том, что proguard будет запутывать и переименовывать атрибуты XML и метод класса, поэтому не на 100% безопаснее, чтобы в один прекрасный день у них никогда не было ошибки.
Итак, если вы никогда не хотите иметь проблемы и никогда не задумываетесь об этом, лучше использовать setOnClickListener
или библиотеки вроде ButterKnife с аннотацией @OnClick(R.id.button)
Ответ 15
Я пишу этот код в 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) {
}
Ответ 16
Лучший способ сделать это - со следующим кодом:
Button button = (Button)findViewById(R.id.btn_register);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do your fancy method
}
});
Ответ 17
![How android:onclick xml attribute works in Android]()
просто используйте имя метода в значении атрибута android: onClick. Убедитесь, что перед именем метода используется публичное ключевое слово.
Пример Android onClick XML