436 votes

Comment empêcher onItemSelected de se déclencher sur un Spinner nouvellement instancié ?

J'ai pensé à des moyens moins qu'élégants de résoudre ce problème, mais je sais que quelque chose doit m'échapper.

Mon onItemSelected se déclenche immédiatement sans aucune interaction avec l'utilisateur, et c'est un comportement indésirable. Je souhaite que l'interface utilisateur attende que l'utilisateur sélectionne quelque chose avant de faire quoi que ce soit.

J'ai même essayé de configurer l'écouteur dans le fichier onResume() en espérant que ça aiderait, mais ce n'est pas le cas.

Comment puis-je l'empêcher de se déclencher avant que l'utilisateur puisse toucher la commande ?

public class CMSHome extends Activity { 

private Spinner spinner;

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

    // Heres my spinner ///////////////////////////////////////////
    spinner = (Spinner) findViewById(R.id.spinner);
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.pm_list, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);
    };

public void onResume() {
    super.onResume();
    spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}

    public class MyOnItemSelectedListener implements OnItemSelectedListener {

    public void onItemSelected(AdapterView<?> parent,
        View view, int pos, long id) {

     Intent i = new Intent(CMSHome.this, ListProjects.class);
     i.putExtra("bEmpID", parent.getItemAtPosition(pos).toString());
        startActivity(i);

        Toast.makeText(parent.getContext(), "The pm is " +
          parent.getItemAtPosition(pos).toString(), Toast.LENGTH_LONG).show();
    }

    public void onNothingSelected(AdapterView parent) {
      // Do nothing.
    }
}
}

2 votes

Vous pouvez envisager cette solution, elle est facile et pratique. stackoverflow.com/a/10102356/621951

1 votes

Une solution simple consisterait à faire en sorte que le premier élément de la rubrique Spinner vide et intérieur onItemSelected vous pouvez détecter si la chaîne n'est pas vide alors startActivity !

0 votes

Ce modèle fonctionne correctement stackoverflow.com/questions/13397933/

394voto

Brad Points 2253

L'utilisation de Runnables est complètement incorrecte.

Utilisez setSelection(position, false); dans la sélection initiale avant setOnItemSelectedListener(listener)

De cette façon, vous définissez votre sélection sans animation, ce qui entraîne l'appel du listener on item selected. Mais l'écouteur est nul, donc rien n'est exécuté. Ensuite, votre listener est assigné.

Alors suivez cette séquence exacte :

Spinner s = (Spinner)Util.findViewById(view, R.id.sound, R.id.spinner);
s.setAdapter(adapter);
s.setSelection(position, false);
s.setOnItemSelectedListener(listener);

49 votes

+1 Joyau caché ! Le passage de false comme paramètre "animate" n'appelle pas le callback de l'écouteur. Génial !

3 votes

+1 Solution bizarre mais élégante :) Heureusement, je devais déjà appeler setSelection de toute façon...

37 votes

L'écouteur se déclenchera toujours lorsque l'élément d'interface utilisateur Spinner sera assemblé, donc il se déclenchera quoi qu'il en soit, ce qui n'empêche pas le comportement indésirable décrit par le PO. Cela fonctionne très bien si ce n'est pas déclaré pendant ou avant onCreateView(), mais ce n'est pas ce qu'ils ont demandé.

205voto

casaflowa Points 1057

En vous référant à la réponse de Dan Dyer, essayez d'enregistrer la OnSelectListener dans un post(Runnable) méthode :

spinner.post(new Runnable() {
    public void run() {
        spinner.setOnItemSelectedListener(listener);
    }
});

En faisant cela pour moi, le comportement souhaité s'est finalement produit.

Dans ce cas, cela signifie également que l'écouteur ne se déclenche que sur un élément modifié.

1 votes

J'obtiens une erreur disant : La méthode setOnItemSelectedListener(AdapterView.OnItemSelectedListener) dans le type AdapterView<SpinnerAdapter> n'est pas applicable pour les arguments (new Runnable(){}) pourquoi ?

0 votes

N'est-ce pas essentiellement la mise en place d'une condition de course entre le Runnable et le Thread UI ?

6 votes

@theFunkyEngineer - Ce code debe être exécuté à partir de l'une des méthodes du fil principal, par exemple onCreate() , onResume() etc. Dans ce cas, c'est une astuce fantastique, sans danger de condition de course. J'utilise normalement cette astuce dans onCreate() juste après le code de mise en page.

80voto

CommonsWare Points 402670

Je m'attendais à ce que votre solution fonctionne. Je pensais que l'événement de sélection ne se déclencherait pas si vous définissiez l'adaptateur avant de configurer l'écouteur.

Cela dit, un simple indicateur booléen vous permettrait de détecter l'événement de première sélection et de l'ignorer.

15 votes

Ugh, ouais. C'est ce que je voulais dire par une solution inélégante. On dirait qu'il doit y avoir un meilleur moyen. Merci quand même.

5 votes

Ce fil de discussion sur le Dev ml donne plus d'informations à ce sujet : groups.google.com/group/Android-developers/browse_thread/thread/ - Malheureusement, aucune solution n'est donnée...

25 votes

Le processus de mise en place des composants déclenche l'écouteur de sélection. Il faut donc ajouter l'écouteur après la mise en page a été faite. Je n'ai pas réussi à trouver un endroit approprié et direct pour le faire, car la mise en page semble se faire à un moment donné après la fin de l'opération. onResume() y onPostResume() Ainsi, tous les crochets normaux sont terminés au moment de la mise en page.

55voto

karooolek Points 181

J'ai créé une petite méthode utilitaire pour modifier Spinner sans en informer l'utilisateur :

private void setSpinnerSelectionWithoutCallingListener(final Spinner spinner, final int selection) {
    final OnItemSelectedListener l = spinner.getOnItemSelectedListener();
    spinner.setOnItemSelectedListener(null);
    spinner.post(new Runnable() {
        @Override
        public void run() {
            spinner.setSelection(selection);
            spinner.post(new Runnable() {
                @Override
                public void run() {
                    spinner.setOnItemSelectedListener(l);
                }
            });
        }
    });
}

Il désactive l'écouteur, modifie la sélection, et réactive l'écouteur après cela.

Le problème, c'est que les appels sont asynchrones par rapport au thread de l'interface utilisateur, et qu'il faut donc le faire dans des messages consécutifs du gestionnaire.

0 votes

Génial. J'avais plusieurs spinners et j'ai essayé de mettre tous leurs listeners à null avant de mettre leurs valeurs, puis je les ai remis à ce qu'ils étaient censés être, mais pour une raison quelconque, ça n'a pas marché. J'ai essayé cette fonction à la place et ça a marché. Je ne sais pas pourquoi la mienne n'a pas fonctionné, mais celle-ci fonctionne alors je m'en fiche :D

6 votes

À noter : si vous appelez setSpinnerSelectionWithoutCallingListener deux fois rapidement, de sorte que le deuxième appel est effectué alors que le premier a déjà réglé l'écouteur sur null votre spinner sera bloqué avec un null auditeur pour toujours. Je propose la correction suivante : ajouter if (listener == null) return; après spinner.setSelection(selection) .

26voto

Michal Points 288

J'étais dans une situation similaire, et j'ai une solution simple qui fonctionne pour moi.

Il semble que les méthodes setSelection(int position) y setSelected(int position, boolean animate) ont une mise en œuvre interne différente.

Lorsque vous utilisez la deuxième méthode setSelected(int position, boolean animate) avec le drapeau false animate, vous obtenez la sélection sans déclencher l'action. onItemSelected écouteur.

0 votes

La meilleure approche est de ne pas se soucier des appels supplémentaires à onItemSelected, mais de s'assurer qu'il affiche la bonne sélection. Ainsi, en appelant spinner.setSelection(selectedIndex) avant d'ajouter l'écouteur, cela a fonctionné de manière cohérente pour moi.

1 votes

Il n'y a pas de méthode setSelected(int position, boolean animate) pour le spinner

4 votes

L'appel réel dont vous avez besoin est setSelection(int position, boolean animate);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X