Android Spinner: Get the selected item change event
Asked Answered
K

17

455

How can you set the event listener for a Spinner when the selected item changes?

Basically what I am trying to do is something similar to this:

spinner1.onSelectionChange = handleSelectionChange;

void handleSelectionChange(Object sender){
    //handle event
}
Kyliekylila answered 26/8, 2009 at 20:53 Comment(0)
P
902

Some of the previous answers are not correct. They work for other widgets and views, but the documentation for the Spinner widget clearly states:

A spinner does not support item click events. Calling this method will raise an exception.

Better use OnItemSelectedListener() instead:

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
        // your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // your code here
    }

});

This works for me.

Note that onItemSelected method is also invoked when the view is being build, so you can consider putting it inside onCreate() method call.

Perceptive answered 11/11, 2009 at 10:50 Comment(11)
the problem with this is that the onItemSelected method is also invoked when the view is being build. So code that is written in there gets executed on startup as well. Is there a way of executing the containing code only if there is a real item selection invoked by the user?Maladminister
actually that problem can be solved by putting the setOnItemSelectedListener in the override OnStart method and not in the onCreate method. stupid me...Maladminister
I have put the listener in the onStart method, but it's called before the user ever gets to see anything, just like onCreate is, so, in my case where a "proceed" button that is meant to be invisible until the user selects something, the button is made visible upon initial display. Are you saying your experience is different? If so, what are you doing differently in the onStart method that I'm missing?Prove
Use another field inside your anonymous listener to record the first selection, and tell onItemSelected not to do anything unless a selection has been encountered? Just a thought.Leucocyte
But what if the user selects the "default" item, the one up the top? Then onItemSelected(...) is not hit. (I know because I just found this out the hard way.)Foreshore
the problem of onItemSelected being invoked upon Activity creation is also discussed on #2562748Dairying
I would suggest taking advantage of setOnItemSelectedListener being called during construction. Use that as an opportunity to initialize the spinner. Also what I've seen is that the listener is called whether it's added in onStart or onCreate.Baywood
One more way could be to introduce a default option like "Please select " on top of the array , and introduce a condition in the onitemselected , that is told not to do anything if the selectedview.gettext returns "Please Select" .Tippett
I set a class variable int to the number of spinner listeners I will be adding in onCreate and decrement it as each onItemSelected is invoked. Untill it reaches zero they just return.Hazlitt
Is it okay? if i don't put any code within public void onNothingSelected .Trudietrudnak
to avoid invoking when the view is being build use spinner.setSelection(0, false);Defense
S
65
Spinner spnLocale = (Spinner)findViewById(R.id.spnLocale);

spnLocale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
        // Your code here
    } 

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

Note: Remember one thing.

Spinner OnItemSelectedListener event will execute twice:

  1. Spinner initialization
  2. User selected manually

Try to differentiate those two by using flag variable.

Spoil answered 29/4, 2010 at 5:15 Comment(3)
Just set a global Boolean like Boolean initialDisplay = true; And then in your onSelect see if it's true and if it is, don't do whatever else you were going to do on select but set the flag to false, for the next time it's called (when the user actually selects).Prove
Genia S. method doesn't work realy well, because it's true that the first time that will be fired onselect event(on onCreate method), you can exclude this event by global var but if then i need to select the already selected item on spinner(the default item, the first) it will not be fired. I have tried to put a spinner label and exclude it, but it will be visible on Dialog opened. I agree with @Batdude. The Spinner is one screwed up widget.Lease
Also note that if you use Genia S's method and you have multiple spinners using the same onItemSelectedListener, you'll have to either track the initialDisplay of each spinner separately, or count the initial calls until you reach the number of spinners. :-pRath
U
25

You can implement AdapterView.OnItemSelectedListener class in your Activity.

And then use the below line within onCreate()

Spinner spin = (Spinner) findViewById(R.id.spinner);
spin.setOnItemSelectedListener(this);

Then override these two methods:

public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
    selection.setText(items[position]);
}

public void onNothingSelected(AdapterView<?> parent) {
    selection.setText("");
}
Ullyot answered 27/3, 2013 at 11:15 Comment(1)
Original source: commonsware.com/Android/excerpt.pdf#page=10Forestation
G
21

https://mcmap.net/q/80278/-android-spinner-get-the-selected-item-change-event/811625

You can avoid the OnItemSelectedListener() being called with a simple check: Store the current selection index in an integer variable and check within the onItemSelected(..) before doing anything.

E.g:

Spinner spnLocale;

spnLocale = (Spinner)findViewById(R.id.spnLocale);

int iCurrentSelection = spnLocale.getSelectedItemPosition();

spnLocale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
    if (iCurrentSelection != i){
            // Your code here
    }
    iCurrentSelection = i;
    } 

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

Of cause the iCurrentSelection should be in object scope for this to work!

Girlie answered 24/11, 2011 at 15:20 Comment(1)
You can't use a non-final variable within an anonymous inner class. If the iCurrentSelection variable is declared within this anonymous class it will work fine. You could initialise it to -1 so the code gets executed on the first call.Autopilot
P
12

It doesn't matter will you set OnItemSelectedListener in onCreate or onStart - it will still be called during of Activity creation or start (respectively).
So we can set it in onCreate (and NOT in onStart!).
Just add a flag to figure out first initialisation:

private Spinner mSpinner;
private boolean mSpinnerInitialized;

then in onCreate (or onCreateView) just:

mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                if (!mSpinnerInitialized) {
                    mSpinnerInitialized = true;
                    return;
                }

                // do stuff
            }

            public void onNothingSelected(AdapterView<?> adapterView) {
                return;
            }
        });
Putout answered 23/8, 2016 at 13:2 Comment(0)
E
9

Find your spinner name and find id then implement this method.

spinnername.setOnItemSelectedListener(new OnItemSelectedListener() {

    @Override
    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
        // your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // your code here
    }
});
Entrepreneur answered 10/12, 2012 at 5:41 Comment(0)
H
9

For kotlin you can use:

spinner.onItemSelectedListener =  object : AdapterView.OnItemSelectedListener {
    override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
        
    }

    override fun onNothingSelected(p0: AdapterView<*>?) {
        
    }
}

Note: for parameters of onItemSelected method I use custom variable names

Harrod answered 18/7, 2020 at 5:38 Comment(0)
W
8
spinner1.setOnItemSelectedListener(
    new AdapterView.OnItemSelectedListener() {
        //add some code here
    }
);
Winkelman answered 28/8, 2009 at 12:33 Comment(1)
This doesn't address the issue of this callback being called when the spinner is first initiated (thus provoking a response which has nothing to do with an item actually being selected).Prove
B
8

The docs for the spinner-widget says

A spinner does not support item click events.

You should use setOnItemSelectedListener to handle your problem.

Bookerbookie answered 6/11, 2009 at 21:13 Comment(0)
H
4

take a global variable for current selection of spinner:

int currentItem = 0;

spinner_counter = (Spinner)findViewById(R.id.spinner_counter);
String[] value={"20","40","60","80","100","All"};
aa=new ArrayAdapter<String>(this,R.layout.spinner_item_profile,value);
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_counter.setAdapter(aa);

spinner_counter.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if(currentItem == position){
                return; //do nothing
            }
            else
            {
                 TextView spinner_item_text = (TextView) view;
                 //write your code here
            }
            currentItem = position;
        }

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

        }
    });

//R.layout.spinner_item_profile
<?xml version="1.0" encoding="utf-8"?>

<TextView  android:id="@+id/spinner_item_text"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" 
android:layout_height="wrap_content"
android:background="@drawable/border_close_profile"
android:gravity="start"  
android:textColor="@color/black"         
android:paddingLeft="5dip"
android:paddingStart="5dip"
android:paddingTop="12dip"
android:paddingBottom="12dip"
/>

//drawable/border_close_profile
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
   <shape android:shape="rectangle">
    <solid android:color="#e2e3d7" />
   </shape>
 </item>
<item android:left="1dp"
android:right="1dp"
android:top="1dp"
android:bottom="1dp">
<shape android:shape="rectangle">
    <solid android:color="@color/white_text" />
</shape>
</item>
</layer-list>
Hairsplitter answered 27/7, 2016 at 4:34 Comment(0)
V
4

If you want a true onChangedListener(). Store the initial value in the handler and check to see if it has changed. It is simple and does not require a global variable. Works if you have more than one spinner on the page.

String initialValue = // get from Database or your object
mySpinner.setOnItemSelectedListener(new SpinnerSelectedListener(initialValue));

...

protected class SpinnerSelectedListener implements AdapterView.OnItemSelectedListener {

        private SpinnerSelectedListener() {
            super();
        }

        public SpinnerSelectedListener(String initialValue) {
            this();
            this.initialValue = initialValue;
        }

        private String initialValue;

        // getter and setter removed.  

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            final String newValue = (String) spinHeight.getItemAtPosition(position);
            if (newValue.equals(initialValue) == false) {
               // Add your code here.  The spinner has changed value. 

               // Maybe useful.   
               // initialValue = newValue;
            }

        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
               // Maybe useful.   
               // initialValue = null; 
        }
    }

Objects are your friend, use them.

Vookles answered 21/11, 2016 at 23:0 Comment(0)
H
3
spinner.setOnItemSelectedListener(
            new AdapterView.OnItemSelectedListener() {

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

                    // TODO Auto-generated method stub
                }

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

                }
                //add some code here
            }
        );
Haplography answered 11/11, 2013 at 16:7 Comment(0)
K
3

By default, you will get the first item of the spinner array through

value = spinner.getSelectedItem().toString();

whenever you selected the value in the spinner this will give you the selected value

if you want the position of the selected item then do it like that

pos = spinner.getSelectedItemPosition();

the above two answers are for without applying listener

Keelia answered 23/1, 2020 at 5:20 Comment(0)
J
2

This will work intialize the spinner and findviewbyid and use this it will work

    Spinner schemeStatusSpinner;

  schemeStatusSpinner = (Spinner) dialog.findViewById(R.id.spinner);

schemeStatusSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            // your code here
            if(schemeStatusSpinner.getSelectedItemId()==4){
                reasonll.setVisibility(View.VISIBLE);
            }
            else {
                reasonll.setVisibility(View.GONE);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parentView) {
            // your code here
        }

    });
Jardine answered 9/1, 2019 at 13:2 Comment(0)
E
1

The best way what I think would be to have an flagitemselected = 0; in onCreate(). And on item selected event increment that flag i.e flagitemselected++; and then check

if(flagitemselected!=1)
{
// do your work here
}

This will help I guess.

Eudosia answered 16/3, 2012 at 7:50 Comment(0)
C
1

I know this was long solved but I have a "Please select" string at the top of my string arrays. Then when you write the listener

yourspinner.onItemSelectedListener = object : OnItemSelectedListener {
            override fun onItemSelected(adapterView: AdapterView<*>?, view: View, i: Int, l: Long) {
                yourvalue = yourspinner.getSelectedItem().toString()

                when(yourvalue){
                    "Please Select" -> // DO nothing
                    else -> // Do something
                }
            }

            override fun onNothingSelected(adapterView: AdapterView<*>?) {
                return
            }
        }

You can of course extend the when statement to have different responses or actions.

Columbus answered 24/11, 2020 at 21:1 Comment(0)
W
0

One trick I found was putting your setOnItemSelectedListeners in onWindowFocusChanged instead of onCreate. I haven't found any bad side-effects to doing it this way, yet. Basically, set up the listeners after the window gets drawn. I'm not sure how often onWindowFocusChanged runs, but it's easy enough to create yourself a lock variable if you are finding it running too often.

I think Android might be using a message-based processing system, and if you put it all in onCreate, you may run into situations where the spinner gets populated after it gets drawn. So, your listener will fire off after you set the item location. This is an educated guess, of course, but feel free to correct me on this.

Willin answered 10/8, 2012 at 18:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.