En quoi l'attribut android:onClick XML diffère-t-il de setOnClickListener?
D'après ce que j'ai lu, vous pouvez assigner un onClick
handler à un bouton de deux façons.
utilisant l'attribut XML android:onClick
où vous n'utilisez que le nom d'une méthode publique avec la signature void name(View v)
ou en utilisant la méthode setOnClickListener
où vous passez un objet qui implémente l'interface OnClickListener
. Ce dernier nécessite souvent une classe anonyme que personnellement je n'aime pas (goût personnel) ou la définition d'une classe interne qui met en œuvre le OnClickListener
.
en utilisant L'attribut XML vous avez juste besoin de définir une méthode au lieu d'une classe donc j'étais je me demande si l'on peut faire la même chose avec du code et pas dans la mise en page XML.
16 réponses
non, ce n'est pas possible via le code. Android implémente juste le OnClickListener
pour vous lorsque vous définissez l'attribut android:onClick="someMethod"
.
ces deux extraits de code sont égaux, juste implémentés de deux façons différentes.
Mise En Œuvre 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 est une implémentation de code d'un OnClickListener
. Et c'est le XML de mise en œuvre.
Mise en œuvre 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 sur un événement de clic.
notez qu'avec le XML ci-dessus, Android recherchera la onClick
méthode myFancyMethod()
seulement dans l'activité courante. C'est important de se rappeler si vous utilisez des fragments, car même si vous ajoutez le XML ci-dessus en utilisant un fragment, Android ne cherchera pas la méthode onClick
dans le .java
fichier du fragment utilisé pour ajouter le XML.
autre chose importante que j'ai remarqué. Vous avez mentionné que vous ne préférez pas anonyme méthodes . Vous vouliez dire que vous n'aimez pas les cours anonymes 1519150920".
quand j'ai vu la réponse du haut, cela m'a fait réaliser que mon problème n'était pas de mettre le paramètre (Vue v) sur la méthode de fantaisie:
public void myFancyMethod(View v) {}
pour y accéder à partir du xml, il faut utiliser
android:onClick="myFancyMethod"/>
Espère que ça aide quelqu'un.
android:onClick
est pour les API de niveau 4, donc si vous ciblez < 1.6, alors vous ne pouvez pas l'utiliser.
spécifiant android:onClick
donne l'attribut Button
appel d'instance setOnClickListener
interne. Il n'y a donc absolument aucune différence.
pour avoir une compréhension claire, voyons comment L'attribut XML onClick
est traité par le framework.
Lorsqu'un fichier de mise en page est gonflé, toutes les vues qui y sont spécifiées sont instanciées. Dans ce cas précis, l'instance Button
est créée en utilisant public Button (Context context, AttributeSet attrs, int defStyle)
constructeur. Tous les attributs de la balise XML sont lus à partir du faisceau de ressources et passés comme AttributeSet
au constructeur.
Button
la classe est héritée de View
de la classe qui se traduit par View
constructeur appelle, qui prend soin de réglage de la cliquez sur retour d'appel du gestionnaire par l'intermédiaire de setOnClickListener
.
l'attribut onClick défini dans attire.xml , est référé en vue.java R.styleable.View_onClick
.
Voici le code de View.java
qui fait la plupart 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 voir, setOnClickListener
est appelé à inscrire le rappel, comme nous le faisons dans notre code. La seule différence est qu'il utilise Java Reflection
pour invoquer la méthode de rappel définie dans notre activité.
Voici la raison des questions mentionnées dans d'autres réponses:
- méthode de Rappel doit être public : Depuis
Java Class getMethod
est utilisé, seules les fonctions d'accès public spécificateur sont recherchés. Autrement être prêt à manipulerIllegalAccessException
exception. - lors de L'Utilisation du bouton avec onClick in Fragment, le callback doit être défini dans L'activité :
getContext().getClass().getMethod()
call restreint la recherche de méthode au contexte actuel, qui est L'activité en cas de Fragment. Par conséquent, la méthode est recherchée dans une classe D'activité et non dans une classe de fragments. - méthode de Rappel doit accepter Afficher le paramètre : Depuis
Java Class getMethod
recherche de la méthode qui accepte deView.class
comme paramètre.
notez que si vous voulez utiliser la fonctionnalité onClick XML, 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 sa chaîne de noms: android:onClick="MyFancyMethod"
mais la déclaration de méthode doit indiquer:
...MyFancyMethod(View v) {...
si vous essayez d'ajouter cette caractéristique à un article de menu , il aura le même exact syntaxe dans le fichier XML mais votre méthode sera déclarée comme: ...MyFancyMethod(MenuItem mi) {...
il y a très bien des réponses ici, mais je veux ajouter une ligne:
dans android:onclick
en XML, Android utilise java reflection derrière la scène pour gérer cela.
Et comme expliqué ici, réflexion toujours ralentit les performances. (en particulier sur Dhalvik VM). Enregistrer onClickListener
est une meilleure façon.
avec Java 8, Vous pouvez probablement utiliser méthode de référence pour obtenir ce que vous voulez.
supposons que c'est votre 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 définir une classe anonyme par vous-même. Je dois toutefois, insistez sur le fait que la référence de la méthode Java 8 n'est en fait qu'un sucre syntaxique. Il crée en fait une instance de la classe anonymous pour vous (tout comme lambda expression l'a fait) donc la même prudence que lambda-expression-style event handler a été appliquée lorsque vous venez à la désinscription de votre event handler. Ce article explique vraiment agréable.
PS. Pour ceux qui sont curieux de savoir comment puis-je vraiment utiliser Java 8 langue fonctionnalité dans Android, il est une courtoisie de retrolambda bibliothèque.
une autre façon de définir vos écouteurs de clic serait D'utiliser XML. Il suffit d'ajouter l'attribut android:onClick à votre balise.
c'est une bonne pratique d'utiliser l'attribut xml" onClick " sur une classe Java anonyme autant que possible.
tout d'abord, regardons la différence de code:
attribut XML / attribut onClick
portion XML
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:onClick="showToast"/>
Java partie
public void showToast(View v) {
//Add some logic
}
Anonymes Classe Java / setOnClickListener
Portion XML
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Java partie
findViewById(R.id.button1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
//Add some logic
}
});
Voici les avantages d'utiliser L'attribut XML sur une classe Java anonyme:
- avec la classe Java anonyme nous devons toujours spécifier un id pour notre éléments, mais avec L'attribut ID XML peut être omis.
- avec la classe Java anonyme nous devons rechercher activement l'élément à l'intérieur de la vue (findViewById portion), mais avec l'attribut XML Androïde le fait pour nous.
- classe Java anonyme nécessite au moins 5 lignes de code, comme nous pouvons voir, mais avec l'attribut XML 3 lignes de code est suffisant.
- avec la classe Java anonyme nous devons nommer notre méthode " onClick", mais avec L'attribut XML nous pouvons ajouter tout nom que nous voulons, qui sera aide spectaculaire avec la lisibilité de notre code.
- XML" onClick " attribut a été ajouté par Google au niveau de L'API 4 release, ce qui signifie qu'il est un peu plus moderne syntaxe et moderne la syntaxe est presque toujours la meilleure.
bien sûr, il n'est pas toujours possible d'utiliser l'attribut Xml, voici les raisons pour lesquelles nous n'aurions pas choisi:
- Si nous travaillons avec fragment. attribut onClick ne peut être ajouté pour une activité, donc si nous avons un fragment, nous devrions utiliser un la classe anonyme.
- si nous voulons déplacer l'auditeur onClick dans une classe séparée (peut-être que si c'est très compliqué et/ou nous tenons à le réutiliser dans les différentes parties de notre application), alors nous ne voulons pas utiliser le attribut xml.
en utilisant L'attribut XML vous avez juste besoin de définir une méthode au lieu de une classe donc je me demandais si la même chose peut être faite par code et pas dans la mise en page XML.
Oui, Vous pouvez faire votre fragment
ou activity
mettre en œuvre View.OnClickListener
et lorsque vous initialisez vos nouveaux objets de vue dans le code, vous pouvez simplement faire mView.setOnClickListener(this);
et cela règle automatiquement toutes les vues objets dans le code pour utiliser la méthode onClick(View v)
que votre fragment
ou activity
etc. a.
pour distinguer quelle vue a appelé la méthode onClick
, vous pouvez utiliser une instruction de commutation sur la méthode v.getId()
.
cette réponse est différente de celle qui dit "non qui n'est pas possible via le code "
Soutenir Ruivo réponse, oui, vous devez déclarer la méthode "public" pour pouvoir l'utiliser dans Android XML onclick - je suis le développement d'une application de ciblage de l'API de Niveau 8 (minSdk...) à 16 (targetSdk...).
Je déclarais ma méthode comme privée et elle a causé l'erreur, la déclarant simplement comme des travaux publics grands.
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;
}}
Supposez, vous voulez ajouter l'événement de clic 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 cette méthode.
public void register(View view) {
}
j'écris 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 en fragment...
public void register(View view) {
}
la meilleure façon de faire ceci est avec 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
}
});
soyez prudent, bien que android:onClick
XML semble être un moyen pratique pour gérer le clic, l'implémentation setOnClickListener
faire quelque chose de plus que l'ajout du onClickListener
. En effet, il a mis la propriété de la vue clickable
à vrai.
bien que ce ne soit peut-être pas un problème sur la plupart des implémentations Android, selon le constructeur du téléphone, bouton est toujours par défaut à cliquable = vrai mais d'autres constructeurs sur un modèle de téléphone pourrait avoir un cliquable par défaut = faux non sur le Bouton points de vue.
donc définir le XML n'est pas suffisant, vous devez penser tout le temps à ajouter android:clickable="true"
sur le bouton non, et si vous avez un périphérique où la valeur par défaut est cliquable = true et vous oubliez même une fois de mettre cet attribut XML, vous ne remarquerez pas le problème à l'exécution, mais obtiendrez le retour sur le marché quand il sera dans les mains de vos clients !
en outre, nous ne pouvons jamais être sûr de la façon dont proguard obfuscate et renommer les attributs XML et la méthode de classe, donc pas 100% sûr qu'ils n'auront jamais un bug un jour.
donc si vous ne voulez jamais avoir de problèmes et ne jamais y penser, il est préférable d'utiliser setOnClickListener
ou des bibliothèques comme ButterKnife avec annotation @OnClick(R.id.button)