web-dev-qa-db-fra.com

Meilleure pratique pour définir les événements de bouton dans Android

J'ai un Layout défini en XML qui consiste en plusieurs Buttons. 

Actuellement, je le fais dans la méthode OnCreate pour définir les gestionnaires d'événements par rapport aux boutons:

public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button newPicButton = (Button)findViewById(R.id.new_button);
    newPicButton.setOnClickListener(btnListener);
    ..... similarly for other buttons too
    .....
}

À l'intérieur de l'événement Button 's onClick, je lance une caméra Intent pour obtenir une image et à l'intérieur du rappel onActivityResult, je configure à nouveau les gestionnaires d'événements en même temps que View:

protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{ 
    setContentView(R.layout.main);
    Button newPicButton = (Button)findViewById(R.id.new_button);
    newPicButton.setOnClickListener(btnListener);
    ...similarly for other buttons too
}

Je suis nouveau sur Android et cette approche de redéfinir un événement à chaque fois me semble assez sale. J'aimerais savoir quelle est la meilleure pratique pour définir des gestionnaires d'événements de boutons dans des scénarios comme celui-ci.

Edit: coller ma classe complète

public class CameraAppActivity extends Activity 
{
    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button newPicButton = (Button)findViewById(R.id.new_button);
        newPicButton.setOnClickListener(btnListener);
    }

    //---create an anonymous class to act as a button click listener---
    private OnClickListener btnListener = new OnClickListener()
    {

        public void onClick(View v)
        {   
             //Intent newPicIntent = new Intent(v.getContext(), NewPictureActivity.class);
             //startActivityForResult(newPicIntent, 0);
            Intent cameraIntent = new Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(cameraIntent, 999);
        } 

    };  

    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    {  

        setContentView(R.layout.main);
        Button newPicButton = (Button)findViewById(R.id.new_button);
        newPicButton.setOnClickListener(btnListener);

       //if I comment last two lines nothing happens when I click on button

    }  

La question principale est

setContentView(R.layout.main);
Button newPicButton = (Button)findViewById(R.id.new_button);
newPicButton.setOnClickListener(btnListener);

Ré-enregistrer des événements dans onActivityResult .. est-ce la bonne approche? Ou est-ce que je fais quelque chose de mal? Parce que si je ne réenregistre pas l'événement, rien ne se passe lorsque je clique sur le bouton.

66
Haris Hasan

Pourquoi ne pas enregistrer l'événement onClick dans la présentation XML et le gérer ensuite dans le code. Voici comment je le ferais:

<Button
Android:id="@+id/my_btn"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="Click me"
Android:onClick="onBtnClicked">
</Button>

et maintenant créer une méthode qui permettrait de gérer les clics

public void onBtnClicked(View v){
    if(v.getId() == R.id.my_btn){
        //handle the click here
    }
}

Vous pouvez également définir OnClickListener individuellement pour chaque élément du code. Utilisez ensuite les instructions if/else ou switch pour déterminer l’origine.

De cette façon, vous pouvez avoir une méthode qui gère tous les boutons d’une même disposition.

METTRE À JOUR:
Bien que ce soit une approche valable, je recommanderais fortement la deuxième option. C'est plus propre et plus facile à maintenir, surtout lorsque vous travaillez avec des fragments.  

63
Marqs

Voici la meilleure approche avec le code:

  public class MyTest extends Activity implements OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     //... some other code here to init the layout
        Button btn1 = (Button)findViewById(R.id.button1);
        Button btn2 = (Button)findViewById(R.id.button2);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.button1:
                break;
            case R.id.button2:
                break;
        }
    }
}

La nouvelle classe avec une interface n’est utile que si vous souhaitez découpler l’implémentation (lorsque vous souhaitez utiliser le même code de classe ailleurs, déplacez-le dans un autre fichier de classe séparé, etc.), mais en général si vous effectuez des opérations connexes. L'activité en cours et les implémentations onClick dépendent de son exécution en référence aux objets définis. Vous devez absolument utiliser la méthode que j'ai proposée.

La création d’interfaces de classes n’est utile que si vous souhaitez établir une communication entre des classes ou des activités distinctes tout en gardant les choses à part. à part cela, c’est une mauvaise pratique de créer des sous-classes pour cela.

39
DArkO

c'est la meilleure approche

@Override
public void onCreate(Bundle savedInstanceState) {
        button1.setOnClickListener(onClickListener);
        button2.setOnClickListener(onClickListener);
        button3.setOnClickListener(onClickListener);
}

private OnClickListener onClickListener = new OnClickListener() {
     @Override
     public void onClick(final View v) {
         switch(v.getId()){
             case R.id.button1:
                  //DO something
             break;
             case R.id.button2:
                  //DO something
             break;
             case R.id.button3:
                  //DO something
             break;
         }

   }
};
12
Nguyen Minh Binh

Il n'y a pas de meilleure pratique définie. Cela dépend fortement du cas d'utilisation. Vous pouvez les définir dans votre mise en page XML à l'aide de l'attribut onClick du bouton.

Exemple XML:

<!-- Stuff -->
<Button Android:id="@+id/my_button"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:text="Click Me!"
    Android:onClick="myClickMethod" />

Exemple Java:

// stuff
public void myClickMethod(View v) {
    // more stuff
}

De cette façon, vous n’aurez pas à implémenter vous-même la OnClickListener. Vous pouvez attribuer à chaque bouton la même méthode onClick et ensuite simplement décider par action quelle action déclencher ou vous pouvez avoir une méthode séparée pour chaque bouton.

En général, je déconseille d'utiliser une OnClickListener pour plus d'un bouton. Il est plus facile de comprendre ce que chaque auditeur est censé faire si vous utilisez des noms descriptifs, ce que vous devriez faire de toute façon.

8
Octavian Damiean

J'aime la méthode "moderne" de DI en utilisant Butter Knife :

  1. Déclarez votre vue
@InjectView(R.id.buttonAlert) 
Button buttonAlert;
  1. Injecter toutes les ressources annotées
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.inject(this);
 }
  1. Annoter et implémenter votre méthode onClick
@OnClick(R.id.buttonAlert)
public void alertClicked(View v){
    // your logic
}
7
funcoder

@ Hasan C'est la meilleure approche que j'ai trouvée et qui me convient parfaitement à chaque fois. 

  • Dans Layout.xml, définissez onClick pour le bouton

                    <Button Android:id="@+id/Button01"          
                        Android:onClick="@string/method" 
                        Android:focusable="true" Android:clickable="true"
                        ">
                    </Button>
    
  • Dans le fichier R.string, ajoutez la ligne suivante

string name = "method"> buttonFunction

  • Dans le fichier sample.Java, la fonction définie dans R.string sera appelée par un clic sur le bouton et devrait ressembler à quelque chose comme: 

    public void buttonFunction (View View) { // ne rien faire comme sur le clic du bouton }

2
Nitin

Voici comment je l'ai fait: 

  1. Dans le fichier de boutons XML, définissez Android: onClick = "onClick".
  2. Implémentez View.OnClickListener dans votre activité.
  3. Dans la méthode onClick, utilisez la touche Switch (voir ci-dessous).

@Passer outre

public void onClick(View view) {
    Intent intent;
    switch(view.getId()){

        case R.id.home_button:
            //DO something
            intent = new Intent(HashTagActivity.this,MainActivity.class);
            startActivity(intent);
            break;
        case R.id.back_button:
            //DO something
             intent = new Intent(HashTagActivity.this,ClassActivity.class);
            startActivity(intent);
            break;
        case R.id.favorite_button:
            //DO something
            break;
        case R.id.copy_button:
            //DO something

            break;

    }
}

Cela fonctionne très bien.

Je sais que c'est vieux, mais si quelqu'un se demande pourquoi vous ne pouvez pas ajouter onClickListener à partir de onActivityResult, c'est parce que le bouton est nul. Si vous l'initialisez une nouvelle fois (comme vous l'avez fait dans onCreate), vous pouvez ajouter le programme d'écoute. Soyez prudent, cependant, tout le reste sera également nul, donc si vous prenez des données à partir d'une EditText, par exemple, vous devez l'initialiser également (un simple contrôle si l'objet est null dans la liste fera l'affaire ).

0
Yordan Lyubenov

Votre activité doit implémenter OnClickListener et vous devez écrire toute votre gestion des événements pour tous les boutons de la seule méthode OnCLick (). 

0
Sujit

Le problème est que l'objet pour le bouton newPicButton est créé en tant qu'objet local qui est valide uniquement dans l'étendue de la fonction onCreate et dès que le code quitte cette fonction, le collecteur garabage libère l'objet pour le bouton. Ce que vous devez faire est de déclarer l'objet newPicButton en dehors de toute méthode, puis dans la méthode onCreate, affectez-lui un écouteur. Cela résoudra votre problème et j'espère avoir expliqué pourquoi rien ne se passe lorsque vous supprimez le code du newPicButton dans la méthode onActivityResult :)

0
Nitin