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!
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:
À 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é.
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:
currentPos1
, currentPos2
)onItemSelectedListener()
appellent une méthode comme refreshMyResult()
ou peu importe.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.
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.
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.
Spinner.setSelection (int position, boolean animate) déclenche l'auditeur sur 4.3
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
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)
Ajoutez la OnItemSelectedListener
pour chaque spinner après vous avez défini une valeur précédente dans onResume
.
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);
This following method will help you to stop invoking automatically the selection listener
yourspinnerobj.post(new Runnable() {
@Override
public void run() {
yourspinnerobj.setOnItemSelectedListener(yourspinnerlistener);
}
});