wake-up-neo.com

So deaktivieren Sie den Aufruf von onItemSelectedListener, wenn das ausgewählte Element durch Code festgelegt wird

Ich frage mich nur, wie Sie mit dem folgenden Problem umgehen: Ein Ergebnis wird abhängig von zwei ausgewählten Spinnern berechnet. Um mit den UI-Dingen umzugehen, d. H. Ein Benutzer wählt ein neues Element in einem der Spinner aus. Ich installiere einen Listener mit setOnItemSelectedListener für den Spinner in meiner onCreate()-Methode der Aktivität.

Nun, das funktioniert natürlich gut. Die Arbeit des Hörers besteht darin, eine neue Berechnung des Ergebnisses auszulösen.

Das Problem: Weil ich onPause()onResume() abfange, um den letzten Status zu speichern/wiederherzustellen, habe ich eine Methode erhalten, die setzt das ausgewählte Element dieser beiden Spinner programmgesteuert wie hier:

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

Diese beiden Anrufe rufen auch die Zuhörer auf! Meine Berechnungsmethode für das Ergebnis sowie die Benachrichtigung über eine neue Ergebnismenge wird hier zweimal aufgerufen.

Ein blöder direkter Ansatz für dieses Vorgehen wäre, eine boolesche Variable zu haben, die deaktiviert, was auch immer der Listener im Inneren tut, diese zu setzen, bevor die ausgewählten Elemente gesetzt und danach zurückgesetzt werden. Aber gibt es eine bessere Methode?

Ich möchte nicht, dass Listener durch Code aufgerufen werden - Aktionen, nur durch Benutzeraktionen! :-(

Wie machst du das? Danke!

31
Zordid

Ich habe eine einfachere und meiner Meinung nach bessere Lösung. Da ich die Spinner auch nach der Initialisierung auffrischen musste, ist dies ein generischer Ansatz.

Unerwünschte onItemSelected-Aufrufe

5
Vedavyas Bhat

Eine sauberere Lösung, um zwischen programmatischen und vom Benutzer initiierten Änderungen zu unterscheiden, ist meiner Meinung nach die folgende:

Erstellen Sie den Listener für den Spinner als OnTouchListener und 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;
        }
    }

}

Fügen Sie den Listener dem Spinner hinzu, der sich für beide Ereignistypen registriert

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

Auf diese Weise werden unerwartete Aufrufe Ihrer Handler-Methode aufgrund der Initialisierung oder Neuinitialisierung ignoriert.

44
Andres Q.

Okay, ich habe es so laufen lassen, wie ich es jetzt möchte.

Die Sache, die hier zu verstehen ist (und ich habe es nicht getan, als ich diese Frage schrieb ...) ist, dass alles in Android in einem Thread läuft - dem UI-Thread.

Das bedeutet: Auch wenn Sie die Werte von Spinner hier und dort einstellen: Sie werden nur aktualisiert (visuell) und ihre Zuhörer werden nur als after alle Methoden bezeichnet, in denen Sie sich gerade befinden (wie onCreate, onResume oder was auch immer) fertig.

Dies ermöglicht Folgendes:

  • belassen Sie die ausgewählten Positionen in Feldvariablen. (wie currentPos1, currentPos2)
  • die Zuhörer onItemSelectedListener() rufen eine Methode wie refreshMyResult() oder wie auch immer auf.
  • wenn Sie Positionen programmgesteuert festlegen, stellen Sie die Spinner und direkt danach manuell ein.

Die refreshMyResult()-Methode sieht folgendermaßen aus:

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!

}

Da die Listener später aufgerufen werden - und bis dahin ist die gespeicherte Position in currentPos bereits aktualisiert - wird nichts geschehen und es wird keine unnötige Aktualisierung von irgendetwas anderem stattfinden .. Wenn ein Benutzer einen neuen Wert in einem der Spinner auswählt na ja - das Update wird entsprechend durchgeführt!

Das ist es! :-)

Ahh - noch etwas: Die Antwort auf meine Frage lautet: Nein. Die Hörer können nicht (einfach) deaktiviert werden und werden aufgerufen, wenn ein Wert geändert wird.

11
Zordid

Fügen Sie zunächst boolesche Werte hinzu, um den Listener-Aufruf von Spinner zu stoppen 

  Boolean check = false;

Dann fügen Sie einen Touch-Listener hinzu, und klicken Sie unter Artikel auf Listener Like 

 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
               }
           });

Es ist einfach, um Serveranrufe mehrmals zu stoppen.

3
Venkatesh

Es ist sehr einfach, die Spinner.setSelection(int position, boolean animate)-Methode mit false aufzurufen, damit die Listener nicht auf die Änderung reagieren.

2
joe

Spinner.setSelection (int position, boolean animate) löst den Listener auf 4.3 aus

2
P01550n

Ich habe eine Bibliothek erstellt, die allen hilft, das Element nicht mit der Aktion "Clicken" in Spinner .__ aufzurufen. Zum Beispiel: 

spinner.setSelection(withAction,position);

wobei withAction ein boolesches Flag ist, das für die Aufruf- oder Nicht-Elementaktion verwendet wird

Link auf Github: https://github.com/scijoker/spinner2

2
a.black13

Wenn Spinner.setSelection (Position) verwendet wird, wird immer setOnItemSelectedListener () aktiviert.

Um zu vermeiden, dass der Code zweimal ausgelöst wird, verwende ich diese Lösung:

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) {
    }
});

Diese Lösung ist gültig, wenn Sie sicher sind, dass Spinner.setSelection (Position) verwendet wurde. Es ist auch wichtig, vor der Verwendung von Spinner.setSelection (Position) jedes Mal mIsSpinnerFirstCall = true festzulegen.

1
Ivo Stoyanov

Fügen Sie die OnItemSelectedListener für jeden Spinner after hinzu, den Sie in onResume zuvor festgelegt haben.

1
Graeme Duncan

Meine Lösung ist sehr einfach. Initialisieren Sie zuerst eine globale boolesche Variable.

boolean shouldWork = true;

Verwenden Sie anschließend den folgenden Code in Ihrer onCreate () - Methode.

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)  {

    }
});

Jetzt können Sie die Methode setSelection in everwhere verwenden, ohne die Methode onItemSelected () mit dem folgenden Code aufzurufen.

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