À partir de là, j'ai lu que vous pouvez affecter un gestionnaire onClick
à un bouton de deux manières.
Utilisation de l'attribut XML Android:onClick
dans lequel vous utilisez simplement le nom d'une méthode publique avec signaturevoid name(View v)
ou à l'aide de la méthode setOnClickListener
dans laquelle vous passez un objet implémentant l'interface OnClickListener
. Ce dernier nécessite souvent une classe anonyme que je n'aime pas personnellement (goût personnel) ou la définition d'une classe interne qui implémente la OnClickListener
.
En utilisant l'attribut XML, il vous suffit de définir une méthode au lieu d'une classe, alors je me demandais si la même chose pouvait être faite via du code et non dans la présentation XML.
Non, ce n'est pas possible via code. Android implémente simplement la OnClickListener
pour vous lorsque vous définissez l'attribut Android:onClick="someMethod"
.
Ces deux extraits de code sont égaux, ils sont simplement implémentés de deux manières différentes.
Implémentation du code
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
}
Ci-dessus, une implémentation de code d'un OnClickListener
. Et ceci est l'implémentation XML.
implémentation 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 arrière-plan, Android ne fait rien d'autre que le code Java, appelant votre méthode lors d'un événement click.
Notez qu'avec le XML ci-dessus, Android recherchera la méthode onClick
myFancyMethod()
uniquement dans l'activité en cours. Il est important de se rappeler que vous utilisez des fragments, car même si vous ajoutez le code XML ci-dessus à l'aide d'un fragment, Android ne cherchera pas la méthode onClick
dans le fichier .Java
de le fragment utilisé pour ajouter le XML.
Une autre chose importante que j'ai remarquée. Vous avez mentionné que vous ne préfériez pas les méthodes anonymes . Vous vouliez dire que vous n'aimez pas les anonymes classes.
Quand j'ai vu la réponse en haut, cela m'a fait comprendre que mon problème n'était pas de placer le paramètre (View v) sur la méthode de fantaisie:
public void myFancyMethod(View v) {}
Lorsque vous essayez d'y accéder à partir du xml, vous devez utiliser
Android:onClick="myFancyMethod"/>
J'espère que ça aide quelqu'un.
Android:onClick
est destiné aux API de niveau 4 et supérieur. Par conséquent, si vous ciblez <1,6, vous ne pourrez pas l'utiliser.
Vérifiez si vous avez oublié de rendre la méthode publique!
La spécification de l'attribut _Android:onClick
_ a pour résultat que Button
instance appelle setOnClickListener
en interne. Il n'y a donc absolument aucune différence.
Pour bien comprendre, voyons comment l'attribut XML onClick
est géré par le framework.
Lorsqu'un fichier de présentation est gonflé, toutes les vues spécifiées sont instanciées. Dans ce cas spécifique, l'instance Button
est créée à l'aide du constructeur public Button (Context context, AttributeSet attrs, int defStyle)
. Tous les attributs de la balise XML sont lus à partir du groupe de ressources et transmis sous la forme AttributeSet
au constructeur.
La classe Button
est héritée de la classe View
qui entraîne l'appel du constructeur View
qui prend en charge le paramétrage du gestionnaire de rappel au clic via setOnClickListener
.
L'attribut onClick défini dans attrs.xml est désigné dans View.Java par _R.styleable.View_onClick
_.
Voici le code de View.Java
qui effectue la majeure partie du travail pour vous en appelant setOnClickListener
par lui-même.
_ 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;
_
Comme vous pouvez le constater, setOnClickListener
est appelé pour enregistrer le rappel, comme nous le faisons dans notre code. La seule différence est qu'il utilise _Java Reflection
_ pour appeler la méthode de rappel définie dans notre activité.
Voici la raison des problèmes mentionnés dans d'autres réponses:
Java Class getMethod
est utilisé, seules les fonctions avec spécificateur d'accès public sont recherchées. Sinon, soyez prêt à gérer l'exception IllegalAccessException
.getContext().getClass().getMethod()
restreint la recherche de méthode au contexte actuel, à savoir Activity en casse. de fragment. Par conséquent, la méthode est recherchée dans la classe d'activité et non dans la classe de fragments.Java Class getMethod
recherche une méthode qui accepte _View.class
_ en tant que paramètre .Notez que si vous souhaitez utiliser la fonctionnalité XML onClick, la méthode correspondante doit avoir un paramètre dont le type doit correspondre à l'objet XML.
Par exemple, un bouton sera lié à votre méthode par son nom: Android:onClick="MyFancyMethod"
mais la déclaration de la méthode doit afficher: ...MyFancyMethod(View v) {...
.
Si vous essayez d'ajouter cette fonctionnalité à un élément de men, la syntaxe sera exactement la même dans le fichier XML, mais votre méthode sera déclarée comme: ...MyFancyMethod(MenuItem mi) {...
Il y a de très bonnes réponses ici, mais je veux ajouter une ligne:
Dans Android:onclick
en XML, Android utilise réflexion Java derrière la scène pour gérer cela.
Et comme expliqué ici la réflexion ralentit toujours la performance. (surtout sur Dhalvik VM). Enregistrer onClickListener
est un meilleur moyen.
Un autre moyen de définir vos écouteurs au clic consiste à utiliser XML. Ajoutez simplement l'attribut Android: onClick à votre tag.
Il est recommandé d'utiliser l'attribut xml "onClick" sur une classe anonyme Java lorsque cela est possible.
Tout d’abord, regardons la différence de code:
attribut XML/attribut onClick
Partie XML
<Button
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:id="@+id/button1"
Android:onClick="showToast"/>
Partie Java
public void showToast(View v) {
//Add some logic
}
Anonymous Java Class/setOnClickListener
Partie XML
<Button
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"/>
Partie Java
findViewById(R.id.button1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
//Add some logic
}
});
Voici les avantages de l'utilisation de l'attribut XML sur une classe Java anonyme:
Bien sûr, il n’est pas toujours possible d’utiliser l’attribut XML, voici les raisons pour lesquelles nous ne l’aurions pas choisi:
En utilisant l'attribut XML, il vous suffit de définir une méthode au lieu d'une classe, alors je me demandais si la même chose pouvait être faite via du code et non dans la présentation XML.
Oui, vous pouvez rendre votre fragment
ou activity
implémenter View.OnClickListener
et lorsque vous initialisez vos nouveaux objets de vue dans le code, vous pouvez simplement faire mView.setOnClickListener(this);
et ceci configure automatiquement tous les objets de vue du code pour utiliser la méthode onClick(View v)
que votre fragment
ou activity
etc.
pour distinguer la vue qui a appelé la méthode onClick
, vous pouvez utiliser une instruction switch sur la méthode v.getId()
.
Cette réponse est différente de celle qui dit "Non, ce n'est pas possible via un code"
Avec Java 8, vous pourriez probablement utiliser Référence de la méthode pour obtenir ce que vous voulez.
Supposons qu'il s'agit de votre gestionnaire d'événement onClick
pour un bouton.
private void onMyButtonClicked(View v) {
if (v.getId() == R.id.myButton) {
// Do something when myButton was clicked
}
}
Ensuite, vous passez onMyButtonClicked
référence de méthode d’instance dans un appel setOnClickListener()
comme ceci.
Button myButton = (Button) findViewById(R.id.myButton);
myButton.setOnClickListener(this::onMyButtonClicked);
Cela vous permettra d'éviter explicitement de définir vous-même une classe anonyme. Je dois toutefois souligner que la référence de méthode de Java 8 n'est en réalité qu'un sucre syntaxique. En fait, cela crée une instance de la classe anonyme (comme le faisait l'expression lambda), d'où la même prudence que lorsque le gestionnaire d'événements de style expression-lambda était appliqué lorsque vous annulez l'enregistrement de votre gestionnaire d'événements. Ceci article explique vraiment Nice.
PS Pour ceux qui sont curieux de savoir comment puis-je vraiment utiliser la fonctionnalité de langage Java 8 dans Android, cette bibliothèque est une gracieuseté de la bibliothèque retrolambda .
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;
}}
Prenant en charge la réponse de Ruivo, oui, vous devez déclarer la méthode "publique" pour pouvoir utiliser XML onclick d'Android. Je développe une application ciblant les API de niveau 8 (minSdk ...) à 16 (targetSdk ...).
Je déclarais ma méthode privée et cela provoquait une erreur, la déclarant simplement publique fonctionne très bien.
utilisez simplement le nom de la méthode dans Android: valeur de l'attribut onClick. Assurez-vous que le mot clé public est utilisé avant le nom de la méthode.
Soyez prudent, bien que Android:onClick
XML semble être un moyen pratique de gérer les clics, l’implémentation setOnClickListener
fait quelque chose de plus que l’ajout de onClickListener
. En effet, la propriété view clickable
a la valeur true.
Bien que cela ne pose peut-être pas un problème sur la plupart des Android implémentations, selon le constructeur du téléphone, button est toujours défini par défaut sur clickable = true, mais les autres constructeurs de certains modèles de téléphone peuvent avoir une valeur par défaut clickable = false sur les vues non de boutons. .
Donc, définir le code XML ne suffit pas, vous devez penser tout le temps à ajouter Android:clickable="true"
sur un bouton, et si vous avez un périphérique où la valeur par défaut est clickable = true et que vous oubliez même une fois de mettre cet attribut XML, vous ne remarquerez pas le problème au moment de l'exécution mais obtiendrez les commentaires sur le marché quand ce sera entre les mains de vos clients!
De plus, nous ne pouvons jamais être sûrs de la façon dont proguard obfusquera et renommera les attributs XML et la méthode de classe, donc pas sûr à 100% qu’ils n’auront jamais un bogue un jour.
Donc, si vous ne voulez jamais avoir de problèmes et n'y pensez jamais, il est préférable d'utiliser setOnClickListener
ou des bibliothèques comme ButterKnife avec l'annotation @OnClick(R.id.button)
Supposons que vous souhaitiez ajouter un événement click comme ceci 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"/>
Dans le fichier Java, vous devez écrire une méthode comme celle-ci.
public void register(View view) {
}
La meilleure façon de faire est d'utiliser le code suivant:
Button button = (Button)findViewById(R.id.btn_register);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do your fancy method
}
});
Je suis Ecrire ce code dans un fichier 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"/>
Et écrivez ce code dans un fragment ...
public void register(View view) {
}