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.

353
demandé sur Octavian Damiean 2010-11-11 13:38:59

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".

540
répondu Octavian Damiean 2017-02-19 09:22:45

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.

75
répondu jp093121 2018-04-22 01:45:17

android:onClick est pour les API de niveau 4, donc si vous ciblez < 1.6, alors vous ne pouvez pas l'utiliser.

68
répondu James 2014-02-24 10:50:08

vérifiez si vous avez oublié de mettre la méthode publique!

28
répondu Ruivo 2011-08-23 19:06:39

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 à manipuler IllegalAccessException 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 de View.class comme paramètre.
21
répondu Manish Mulimani 2014-08-18 13:07:21

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) {...

13
répondu Antoine Lizée 2013-11-07 19:06:17

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.

11
répondu Krupal Shah 2017-05-23 11:54:59

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.

4
répondu onelaview 2016-04-01 13:31:29

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.
4
répondu Bestin John 2016-06-11 08:36:23

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 "

4
répondu CQM 2017-03-30 16:29:41

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.

3
répondu Waqas Hasan 2012-09-04 13:51:03
   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;
    }}
3
répondu jeet parmar 2015-06-15 14:22:47

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) {
}
0
répondu nazrul islam 2014-12-10 09:10:52

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) {
}
0
répondu user2786249 2015-12-07 13:11:54

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
            }
        });
0
répondu Katarina Dabo 2016-02-14 19:55:40

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)

0
répondu Livio 2017-05-25 15:19:18