web-dev-qa-db-fra.com

Android Spinner: Évitez les appels onItemSelected lors de l'initialisation

J'ai créé une application Android avec une Spinner et une TextView. Ma tâche consiste à afficher l'élément sélectionné dans la liste déroulante de Spinner dans TextView. J'ai implémenté Spinner dans la méthode onCreate de sorte que lorsque j'exécute le programme, il affiche une valeur dans TextView (avant de sélectionner un élément dans la liste déroulante). 

Je souhaite afficher la valeur dans TextView uniquement après avoir sélectionné un élément dans la liste déroulante. Comment puis-je faire cela?

Voici mon code: 

import Android.app.Activity;
import Android.os.Bundle;
import Android.view.View;
import Android.widget.AdapterView;
import Android.widget.AdapterView.OnItemSelectedListener;
import Android.widget.ArrayAdapter;
import Android.widget.Spinner;
import Android.widget.TextView;

public class GPACal01Activity extends Activity implements OnItemSelectedListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Spinner spinner = (Spinner) findViewById(R.id.noOfSubjects);

        // Create an ArrayAdapter using the string array and a default spinner layout
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.noofsubjects_array, Android.R.layout.simple_spinner_item);
        // Specify the layout to use when the list of choices appears
        adapter.setDropDownViewResource(Android.R.layout.simple_spinner_dropdown_item);
        // Apply the adapter to the spinner
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);
    }

    public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
        TextView textView = (TextView) findViewById(R.id.textView1);
        String str = (String) parent.getItemAtPosition(pos);
        textView.setText(str);
    }

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

    }
}
104
Grant
spinner.setOnItemSelectedListener(this); // Will call onItemSelected() Listener.

Donc, la première fois gérer cela avec une valeur Integer

Exemple: Prenez initialement int check = 0;

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
   if(++check > 1) {
      TextView textView = (TextView) findViewById(R.id.textView1);
      String str = (String) parent.getItemAtPosition(pos);
      textView.setText(str);
   }
}

Vous pouvez le faire avec une valeur booléenne et en vérifiant les positions actuelles et précédentes. Vois ici

139
Abhi

Il suffit de mettre cette ligne avant de définir OnItemSelectedListener

spinner.setSelection(0,false)
70

À partir du niveau 3 de l'API, vous pouvez utiliser onUserInteraction () sur une activité avec un booléen pour déterminer si l'utilisateur interagit avec le périphérique.

http://developer.Android.com/reference/Android/app/Activity.html#onUserInteraction ()

@Override
public void onUserInteraction() {
     super.onUserInteraction();
     userIsInteracting = true;
}

En tant que champ de l'activité, j'ai:

 private boolean userIsInteracting;

Enfin, mon spinner:

      mSpinnerView.setOnItemSelectedListener(new OnItemSelectedListener() {

           @Override
           public void onItemSelected(AdapterView<?> arg0, View view, int position, long arg3) {
                spinnerAdapter.setmPreviousSelectedIndex(position);
                if (userIsInteracting) {
                     updateGUI();
                }
           }

           @Override
           public void onNothingSelected(AdapterView<?> arg0) {

           }
      });

Au fur et à mesure que vous avancez dans l'activité, le booléen est remis à faux. Fonctionne comme un charme.

49
Bill Mote

Cela a fonctionné pour moi 

L'initialisation de Spinner dans Android est parfois problématique. Le problème ci-dessus a été résolu par ce motif.

Spinner.setAdapter();
Spinner.setSelected(false);  // must
Spinner.setSelection(0,true);  //must
Spinner.setonItemSelectedListener(this);

L'adaptateur de paramétrage doit être la première partie et onItemSelectedListener (ceci) sera le dernier lors de l'initialisation d'un compteur. Par le motif ci-dessus, mon OnItemSelected () n’est pas appelé lors de l’initialisation de spinner

12
saksham

haha ... J'ai la même question . Quand initViews () fait comme ça. La séquence est la clé, auditeur est le dernier. Bonne chance !

spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);
10
Treesouth

Ma solution:

protected boolean inhibit_spinner = true;


@Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int pos, long arg3) {

            if (inhibit_spinner) {
                inhibit_spinner = false;
            }else {

            if (getDataTask != null) getDataTask.cancel(true);
            updateData();
            }

        }
7
codareee

Vous pouvez le faire de cette manière:

AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            //set the text of TextView
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

yourSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            yourSpinner.setOnItemSelectedListener(listener);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

Au début, je crée un auditeur et l’attribue à un rappel variable; alors je crée un deuxième auditeur anonyme et quand ceci est appelé pour la première fois, cela change le listener

5
Charleston

Une solution simple similaire qui permet à plusieurs filateurs est de placer AdapterView dans une collection - dans la superclasse Activités - lors de la première exécution de onItemSelected (...). Vérifiez ensuite si AdapterView est dans la collection avant de l'exécuter. Cela active un ensemble de méthodes dans la super-classe et prend en charge plusieurs AdapterViews et par conséquent plusieurs spinners.

Superclasse ...

private Collection<AdapterView> AdapterViewCollection = new ArrayList<AdapterView>();

   protected boolean firstTimeThrough(AdapterView parent) {
    boolean firstTimeThrough = ! AdapterViewCollection.contains(parent);
    if (firstTimeThrough) {
       AdapterViewCollection.add(parent);
     }
    return firstTimeThrough;
   }

Sous-classe ...

public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
      if (! firstTimeThrough(parent)) {
        String value = safeString(parent.getItemAtPosition(pos).toString());
        String extraMessage = EXTRA_MESSAGE;
        Intent sharedPreferencesDisplayIntent = new         Intent(SharedPreferencesSelectionActivity.this,SharedPreferencesDisplayActivity.class);
    sharedPreferencesDisplayIntent.putExtra(extraMessage,value);
    startActivity(sharedPreferencesDisplayIntent);
  }
  // don't execute the above code if its the first time through
  // do to onItemSelected being called during view initialization.

}

2
Jonathan Cole

Essaye ça

spinner.postDelayed(new Runnable() {
        @Override
        public void run() {
            addListeners();
        }
    }, 1000);.o
2
Ubirajara Erthal

Vous pouvez y parvenir en définissant setOnTouchListener, puis setOnItemSelectedListener dans onTouch.

@Override
public boolean onTouch(final View view, final MotionEvent event) {
 view.setOnItemSelectedListener(this)
 return false;
}
1
vviieett

L'indicateur d'interaction utilisateur peut ensuite être défini sur true dans la méthode onTouch et réinitialisé dans onItemSelected() une fois que le changement de sélection a été traité. Je préfère cette solution car l'indicateur d'interaction utilisateur est traité exclusivement pour le cinéaste, et non pour les autres vues de l'activité pouvant affecter le comportement souhaité. 

Dans du code:

Créez votre auditeur pour le spinner:

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) { 
            userSelect = false;
            // Your selection handling code here
        }
    }

}

Ajoutez l'auditeur au cinéaste en tant que OnItemSelectedListener et OnTouchListener:

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);
1
Ranjith Kumar

Pour éviter d'appeler spinner.setOnItemSelectedListener () pendant l'initialisation

spinner.setSelection(Adapter.NO_SELECTION, true); //Add this line before setting listener
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
});
1
Ketan Ramani

Avait le même problème et cela fonctionne pour moi:

J'ai 2 disques et je les mets à jour pendant l'init et pendant les interactions avec d'autres contrôles ou après avoir récupéré les données du serveur.

Voici mon modèle:

public class MyClass extends <Activity/Fragment/Whatever> implements Spinner.OnItemSelectedListener {

    private void removeSpinnersListeners() {
        spn1.setOnItemSelectedListener(null);
        spn2.setOnItemSelectedListener(null);
    }

    private void setSpinnersListeners() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                spn1.setOnItemSelectedListener(MyClass.this);
                spn2.setOnItemSelectedListener(MyClass.this);
            }
        }, 1);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        // Your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
}

Lorsque la classe lance l'initialisation, utilisez setSpinnersListeners () au lieu de définir directement l'écouteur.

Le Runnable empêchera la roulette de tirer surItemSelected juste après que vous ayez défini leurs valeurs.

Si vous devez mettre à jour le compteur (après un appel au serveur, etc.), utilisez removeSpinnersListeners () juste avant vos lignes de mise à jour et setSpinnersListeners () juste après les lignes de mise à jour. Cela empêchera le déclenchement de onItemSelected après la mise à jour.

1
RoyBS

créer un champ booléen 

private boolean inispinner;

à l'intérieur de l'activité

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (!inispinner) {
                inispinner = true;
                return;
            }
            //do your work here
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    });
0
Afjalur Rahman Rana