sirve - ¿En qué difiere exactamente el atributo android: onClick XML del setOnClickListener?
setonclicklistener android studio (16)
Desde que leí, puedes asignar un controlador onClick
a un botón de dos maneras.
Utilizando el atributo de android:onClick
donde solo usas el nombre de un método público con el void name(View v)
la firma void name(View v)
o usando el método setOnClickListener
donde pasas un objeto que implementa la interfaz OnClickListener
. Este último a menudo requiere una clase anónima que personalmente no me gusta (gusto personal) o la definición de una clase interna que implementa el OnClickListener
.
Al utilizar el atributo XML, solo necesita definir un método en lugar de una clase, por lo que me preguntaba si se puede hacer lo mismo a través del código y no en el diseño XML.
Al utilizar el atributo XML, solo necesita definir un método en lugar de una clase, por lo que me preguntaba si se puede hacer lo mismo a través del código y no en el diseño XML.
Sí, puedes hacer que tu fragment
o activity
implemente View.OnClickListener
y cuando inicializa sus nuevos objetos de vista en código, simplemente puede hacer mView.setOnClickListener(this);
y esto configura automáticamente todos los objetos de vista en código para usar el método onClick(View v)
que tiene su fragment
o activity
etc.
para distinguir qué vista ha llamado al método onClick
, puede usar una instrucción switch en el método v.getId()
.
Esta respuesta es diferente de la que dice "No, eso no es posible a través del código".
Compruebe si se olvidó de poner el método público!
Con Java 8, probablemente podría usar la Referencia de método para lograr lo que desea.
Supongamos que este es su controlador de eventos onClick
para un botón.
private void onMyButtonClicked(View v) {
if (v.getId() == R.id.myButton) {
// Do something when myButton was clicked
}
}
Luego, pasa la referencia del método de instancia onMyButtonClicked
en una llamada setOnClickListener()
como esta.
Button myButton = (Button) findViewById(R.id.myButton);
myButton.setOnClickListener(this::onMyButtonClicked);
Esto le permitirá evitar la definición explícita de una clase anónima por sí mismo. Sin embargo, debo enfatizar que la Referencia de métodos de Java 8 es en realidad solo un azúcar sintáctico. En realidad, crea una instancia de la clase anónima para usted (al igual que lo hizo la expresión lambda), por lo que se aplicó una precaución similar al uso del controlador de eventos lambda-expresión-estilo cuando llega al desregistro de su controlador de eventos. Este article explica muy bien.
PD. Para aquellos que retrolambda curiosidad por saber cómo puedo usar realmente la función de lenguaje Java 8 en Android, es una cortesía de la biblioteca retrolambda .
Cuando vi la respuesta principal, me di cuenta de que mi problema no era poner el parámetro (Ver v) en el método sofisticado:
public void myFancyMethod(View v) {}
Al intentar acceder a él desde el xml, uno debe usar
android:onClick="myFancyMethod"/>
Espero que ayude a alguien.
Especificar los resultados de los atributos de android:onClick
en la instancia de Button
llama a setOnClickListener
internamente. Por lo tanto, no hay absolutamente ninguna diferencia.
Para tener un entendimiento claro, veamos cómo el marco maneja el atributo XML onClick
.
Cuando se infla un archivo de diseño, se crea una instancia de todas las vistas especificadas en él. En este caso específico, la instancia de Button
se crea utilizando public Button (Context context, AttributeSet attrs, int defStyle)
constructor public Button (Context context, AttributeSet attrs, int defStyle)
. Todos los atributos de la etiqueta XML se leen del paquete de recursos y se pasan como AttributeSet
al constructor.
Button
clase Button
se hereda de la clase View
, lo que da como resultado que se llame al constructor View
, que se encarga de configurar el controlador de devolución de llamadas mediante setOnClickListener
.
El atributo onClick definido en attrs.xml , se refiere en View.java como R.styleable.View_onClick
.
Aquí está el código de View.java
que hace la mayor parte del trabajo llamando a setOnClickListener
por sí mismo.
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;
Como puede ver, se llama a setOnClickListener
para registrar la devolución de llamada, como lo hacemos en nuestro código. La única diferencia es que utiliza Java Reflection
para invocar el método de devolución de llamada definido en nuestra Actividad.
Aquí están las razones de los problemas mencionados en otras respuestas:
- El método de devolución de llamada debe ser público :
Java Class getMethod
se utilizaJava Class getMethod
, solo se buscan las funciones con especificador de acceso público. De lo contrario, esté preparado para manejar la excepciónIllegalAccessException
. - Mientras se usa Button con onClick en Fragmento, la devolución de llamada se debe definir en Actividad :
getContext().getClass().getMethod()
llamada agetContext().getClass().getMethod()
restringe la búsqueda del método al contexto actual, que es Actividad en caso de Fragmento. Por lo tanto, el método se busca dentro de la clase de actividad y no en la clase de fragmento. - El método de devolución de llamada debe aceptar el parámetro View : Ya que
Java Class getMethod
busca el método que aceptaView.class
como parámetro.
Estoy escribe este código en un archivo 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"/>
Y escribe este código en fragmento ...
public void register(View view) {
}
Hay respuestas muy buenas aquí, pero quiero agregar una línea:
En android:onclick
en XML, Android utiliza la reflexión de Java detrás de la escena para manejar esto.
Y como se explica aquí, la reflexión siempre ralentiza el rendimiento. (especialmente en Dhalvik VM). Registrarse onClickListener
es una mejor manera.
La mejor manera de hacerlo es con el siguiente código:
Button button = (Button)findViewById(R.id.btn_register);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do your fancy method
}
});
No, eso no es posible a través del código. Android simplemente implementa el OnClickListener
para usted cuando define el atributo android:onClick="someMethod"
.
Esos dos fragmentos de código son iguales, solo se implementan de dos maneras diferentes.
Implementación de Código
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
}
Arriba hay una implementación de código de un OnClickListener
. Y esta es la implementación de XML.
Implementación 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 -->
En el fondo, Android no hace nada más que el código Java, llamando a su método en un evento de clic.
Tenga en cuenta que con el XML anterior, Android buscará el método onClick
myFancyMethod()
solo en la Actividad actual. Es importante recordar esto si está utilizando fragmentos, ya que incluso si agrega el XML anterior con un fragmento, Android no buscará el método onClick
en el archivo .java
del fragmento utilizado para agregar el XML.
Otra cosa importante que noté. Usted mencionó que no prefiere los métodos anónimos. Querías decir que no te gustan las clases anónimas.
Otra forma de configurar sus oyentes en clic sería utilizar XML. Solo agrega el atributo android: onClick a tu etiqueta.
Es una buena práctica usar el atributo xml "onClick" sobre una clase Java anónima siempre que sea posible.
En primer lugar, echemos un vistazo a la diferencia en el código:
Atributo XML / atributo onClick
Porción XML
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:onClick="showToast"/>
Parte de Java
public void showToast(View v) {
//Add some logic
}
Clase anónima de Java / setOnClickListener
Porción XML
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Parte de Java
findViewById(R.id.button1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
//Add some logic
}
});
Aquí están los beneficios de usar el atributo XML sobre una clase Java anónima:
- Con la clase Java anónima siempre tenemos que especificar un ID para nuestros elementos, pero con el atributo XML se puede omitir el ID.
- Con la clase Java anónima tenemos que buscar activamente el elemento dentro de la vista (parte findViewById), pero con el atributo XML, Android lo hace por nosotros.
- La clase anónima de Java requiere al menos 5 líneas de código, como podemos ver, pero con el atributo XML, 3 líneas de código son suficientes.
- Con la clase anónima de Java, tenemos que nombrar nuestro método "onClick", pero con el atributo XML podemos agregar el nombre que queramos, lo que ayudará enormemente con la legibilidad de nuestro código.
- Google ha agregado el atributo "onClick" de XML durante el lanzamiento del nivel 4 de API, lo que significa que es una sintaxis un poco más moderna y que la sintaxis moderna es casi siempre mejor.
Por supuesto, no siempre es posible usar el atributo Xml, aquí están las razones por las que no lo elegimos:
- Si estamos trabajando con fragmentos. El atributo onClick solo se puede agregar a una actividad, por lo que si tenemos un fragmento, tendríamos que usar una clase anónima.
- Si nos gustaría mover el oyente onClick a una clase separada (tal vez si es muy complicado y / o nos gustaría reutilizarlo en diferentes partes de nuestra aplicación), entonces no queremos usar el atributo xml ya sea.
Respaldando la respuesta de Ruivo, sí, tiene que declarar el método como "público" para poder usarlo en el clic de Android de Android. Estoy desarrollando una aplicación dirigida desde el nivel 8 (minSdk ...) a 16 (targetSdk ...).
Estaba declarando mi método como privado y causó un error, tan solo declararlo como una gran obra pública.
Supongamos que desea agregar un evento de clic como este 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"/>
En el archivo java, tienes que escribir un método como este.
public void register(View view) {
}
Tenga cuidado, aunque android:onClick
XML parece ser una forma conveniente de manejar el clic, la implementación de setOnClickListener
hace algo más que agregar el onClickListener
. De hecho, puso la propiedad vista que se clickable
hacer clickable
en verdadero.
Si bien puede que no sea un problema en la mayoría de las implementaciones de Android, de acuerdo con el constructor del teléfono, el botón siempre es predeterminado para hacer clic = verdadero, pero otros constructores en algún modelo de teléfono pueden tener un clic por defecto = falso en las vistas sin botón.
Por lo tanto, establecer el XML no es suficiente, hay que pensar todo el tiempo para agregar android:clickable="true"
en el botón non, y si tiene un dispositivo donde se puede hacer clic en el valor predeterminado = true y se olvida una sola vez para colocar este XML ¡Atributo, no notará el problema en el tiempo de ejecución, pero obtendrá la retroalimentación en el mercado cuando esté en manos de sus clientes!
Además, nunca podemos estar seguros de cómo proguard ofuscará y renombrará los atributos XML y el método de clase, por lo que no es 100% seguro que nunca tendrán un error algún día.
Entonces, si nunca quieres tener problemas y nunca pensar en ello, es mejor usar setOnClickListener
o bibliotecas como ButterKnife con la anotación @OnClick(R.id.button)
Tenga en cuenta que si desea utilizar la función onClick XML, el método correspondiente debe tener un parámetro, cuyo tipo debe coincidir con el objeto XML.
Por ejemplo, un botón se vinculará a su método a través de su cadena de nombre: android:onClick="MyFancyMethod"
pero la declaración del método debe mostrar: ...MyFancyMethod(View v) {...
Si está intentando agregar esta función a un elemento del menú , tendrá la misma sintaxis exacta en el archivo XML, pero su método se declarará como: ...MyFancyMethod(MenuItem mi) {...
android:onClick
es para API nivel 4 en adelante, por lo que si está apuntando a <1.6, entonces no puede usarlo.
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;
}}