web-dev-qa-db-fra.com

Comment désactiver onItemSelectedListener à invoquer lors de la définition d'un élément sélectionné par code

Vous vous demandez simplement comment vous gérez le problème suivant: un résultat est calculé en fonction des éléments sélectionnés par deux fileurs. Pour gérer l’interface utilisateur, c’est-à-dire qu’un utilisateur sélectionne un nouvel élément dans l’une des machines à filer, j’installe un écouteur en utilisant setOnItemSelectedListener pour le spinner dans ma méthode onCreate() de l’activité.

Maintenant: ça marche, bien sûr, ça va. Le travail de l'auditeur consiste à déclencher un nouveau calcul du résultat.

Le problème: parce que j'intercepte onPause()onResume() pour sauvegarder/restaurer le dernier état, j'ai une méthode qui définit l'élément sélectionné de ces deux fileuses par programmation comme ici:

startSpinner.setSelection(pStart);
destSpinner.setSelection(pDest);

Ces deux appels invoquent également les auditeurs! Ma méthode de calcul pour le résultat plus la notification d'un nouvel ensemble de résultats est invoquée deux fois ici!

Une approche directe stupide pour cela consisterait à avoir une variable booléenne désactivant tout ce que l’auditeur fait à l’intérieur, en la définissant avant de définir les éléments sélectionnés, puis en la réinitialisant par la suite. Mais y a-t-il une meilleure méthode ??

Je ne veux pas que les auditeurs soient appelés par code - actions, seulement par actions! :-(

Comment faites-vous cela? Merci!

31
Zordid

J'ai une meilleure solution, et je pense, meilleure. Comme je devais rafraîchir les disques même après l’initialisation, c’est une approche plus générique ..___ Veuillez vous référer à la réponse acceptée:

Appels non souhaités surItemSelected

5
Vedavyas Bhat

À mon avis, une solution plus propre permettant de différencier les modifications programmatiques des modifications initiées par l'utilisateur est la suivante:

Créez votre auditeur pour spinner en tant que OnTouchListener et OnItemSelectedListener

public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener {

    boolean userSelect = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        userSelect = true;
        return false;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
        if (userSelect) { 
            // Your selection handling code here
            userSelect = false;
        }
    }

}

Ajouter l'auditeur au disque qui s'inscrit pour les deux types d'événement

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);

De cette façon, tout appel inattendu à votre méthode de gestionnaire dû à une initialisation ou à une réinitialisation sera ignoré.

44
Andres Q.

Ok, je l'ai fait fonctionner comme je le veux maintenant.

Ce qu'il faut comprendre ici (ce que je ne savais pas quand j'écrivais cette question ...), c'est que tout dans Android fonctionne en un seul fil - le fil de l'interface utilisateur.

Signification: même si vous définissez les valeurs de Spinner ici et là: elles ne sont mises à jour (visuellement) et que leurs auditeurs s'appellent uniquement après toutes les méthodes dans lesquelles vous êtes actuellement (comme onCreate, onResume ou autre) sont fini.

Cela permet:

  • conserve les positions sélectionnées dans les variables de champ. (comme currentPos1, currentPos2)
  • les auditeurs onItemSelectedListener() appellent une méthode comme refreshMyResult() ou peu importe.
  • lorsque vous définissez des positions par programme, définissez les fileuses et appelez votre propre méthode de rafraîchissement manuellement juste après cela.

La méthode refreshMyResult() ressemble à ceci:

int newPos1 = mySpinner1.getSelectedItemPosition();
int newPos2 = mySpinner2.getSelectedItemPosition();
// only do something if update is not done yet
if (newPos1 != currentPos1 || newPos2 != currentPos2) {
    currentPos1 = newPos1;
    currentPos2 = newPos2;

    // do whatever has to be done to update things!

}

Etant donné que les écouteurs seront appelés plus tard - et à ce moment-là, la position mémorisée dans currentPos est déjà mise à jour - rien ne se passera et aucune mise à jour inutile d'autre chose n'aura lieu . Lorsqu'un utilisateur sélectionne une nouvelle valeur dans l'un des filateurs Eh bien, la mise à jour sera effectuée en conséquence!

C'est tout! :-)

Ahh - encore une chose: la réponse à ma question est: Non ... Les auditeurs ne peuvent pas être désactivés (facilement) et seront appelés chaque fois qu'une valeur est modifiée.

11
Zordid

Ajoutez d'abord des valeurs booléennes pour arrêter l'appel de l'auditeur spinner 

  Boolean check = false;

Ensuite, vous ajoutez un écouteur tactile et un élément, puis cliquez sur Écouteur. 

 holder.filters.setOnTouchListener(new View.OnTouchListener() {
               @Override
               public boolean onTouch(View v, MotionEvent event) {

                   check = true;
                   return false;
               }
           });

           holder.filters.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
           {

               @Override
               public void onItemSelected(AdapterView<?> parent, View arg1, int position, long id)
               {
                   flag = filterids.get(position);

                   if(check)
                   {
                       check = false;
                       new Applyfilters().execute(flag,"3");
                   }else{

                   }

               }

               @Override
               public void onNothingSelected(AdapterView<?> arg0)
               {
                   // TODO Auto-generated method stub
               }
           });

Son fonctionnement simple permet d’arrêter plusieurs fois les appels au serveur.

3
Venkatesh

Il est très facile d'appeler la méthode Spinner.setSelection(int position, boolean animate) avec false pour que les écouteurs ne réagissent pas à la modification.

2
joe

Spinner.setSelection (int position, boolean animate) déclenche l'auditeur sur 4.3

2
P01550n

J'ai créé une bibliothèque qui aide pour tous, sans qu'il soit nécessaire d'appeler l'action onClick d'item dans Spinner Par exemple: 

spinner.setSelection(withAction,position);

où withAction est un indicateur booléen, celui utilisé pour l'action call ou not item

Lien sur Github: https://github.com/scijoker/spinner2

2
a.black13

Lorsque Spinner.setSelection (position) est utilisé, il active toujours setOnItemSelectedListener ().

Pour éviter de tirer le code deux fois, j'utilise cette solution:

private mIsSpinnerFirstCall=true;

...
Spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        //If a new value is selected (avoid activating on setSelection())
        if(!mIsSpinnerFirstCall) {
            // Your code goes gere
        }
        mIsSpinnerFirstCall = false;
    }

    public void onNothingSelected(AdapterView<?> arg0) {
    }
});

Cette solution est valide lorsque vous êtes sûr que Spinner.setSelection (position) us a été utilisé. En outre, il est important de définir mIsSpinnerFirstCall = true à chaque fois avant d'utiliser Spinner.setSelection (position)

1
Ivo Stoyanov

Ajoutez la OnItemSelectedListener pour chaque spinner après vous avez défini une valeur précédente dans onResume.

1
Graeme Duncan

Ma solution est très simple. Commencez par initialiser une variable booléenne globale.

boolean shouldWork = true;

Ensuite, utilisez le code ci-dessous dans votre méthode onCreate ().

Spinner spinner = findViewById(R.id.spinner);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView adapter, View v, int i, long lng) {
        if (shouldWork) {
               // Do your actions here
        }
        else
            shouldWork = true;
    }
    public void onNothingSelected(AdapterView<?> parentView)  {

    }
});

Vous pouvez maintenant utiliser la méthode setSelection à tout moment sans appeler la méthode onItemSelected () avec le code ci-dessous.

shouldWork = false;
spinner.setSelection(0);
1
mstburak
    This following method will help you to stop invoking automatically the selection listener


    yourspinnerobj.post(new Runnable() {
                @Override
                public void run() {
                    yourspinnerobj.setOnItemSelectedListener(yourspinnerlistener);
                }
            });
0
Jaya