Spinner onItemSelected() executes inappropriately

31,866

Solution 1

David, here is a tutorial I wrote up for this problem...

Problem Statement

an undesirable onItemSelected() is triggered whilst the Gallery (or Spinner) is initializing. This means that code is prematurely executed; code which is intended to execute ONLY when a user physically makes a selection.

Solution

  1. in onCreate(), count how many Gallery (or Spinner) widgets you have in the view. (mGalleryCount)
  2. in onItemSelected(), count how often it has triggered. (mGalleryInitializedCount)
  3. when (mGalleryInitializedCount < mGalleryCount) == false, then execute the code meant for the user

Code Example

public class myActivity extends Activity implements OnItemSelectedListener
{
    //this counts how many Gallery's are on the UI
    private int mGalleryCount=0;

    //this counts how many Gallery's have been initialized
    private int mGalleryInitializedCount=0;

    //UI reference
    private Gallery mGallery;


    @Override
    public void onCreate(Bundle savedInstanceState)
    {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.myxmllayout);

        //get references to UI components
        mGallery = (Gallery) findViewById(R.id.mygallery);

        //trap selection events from gallery
        mGallery.setOnItemSelectedListener(this);

        //trap only selection when no flinging is taking place
        mGallery.setCallbackDuringFling(false);

        //
        //do other stuff like load images, setAdapter(), etc
        //

        //define how many Gallery's are in this view
        //note: this could be counted dynamically if you are programmatically creating the view
        mGalleryCount=1;

    }


    public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
    {

        if (mGalleryInitializedCount < mGalleryCount)
        {
            mGalleryInitializedCount++;
        }
        else
        {
            //only detect selection events that are not done whilst initializing
            Log.i(TAG, "selected item position = " + String.valueOf(position) );
        }

    }

}

Why this works

this solution works because the Gallery finishes initialization long before a user is physically able to make a selection.

Solution 2

Here is a modified version of "Someone Somewhere" code. You can use it if you have a single view.

public class myActivity extends Activity implements OnItemSelectedListener
{
// Set view initialization to false while the it is being built
private boolean initializedView = false;

//UI reference
private Gallery mGallery;


@Override
public void onCreate(Bundle savedInstanceState)
{

    super.onCreate(savedInstanceState);
    setContentView(R.layout.myxmllayout);

    //get references to UI components
    mGallery = (Gallery) findViewById(R.id.mygallery);

    //trap selection events from gallery
    mGallery.setOnItemSelectedListener(this);

    //trap only selection when no flinging is taking place
    mGallery.setCallbackDuringFling(false);

    //
    //do other stuff like load images, setAdapter(), etc
    //


}


public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{

    if (initializedView ==  false)
    {
        initializedView = true;
    }
    else
    {
        //only detect selection events that are not done whilst initializing
        Log.i(TAG, "selected item position = " + String.valueOf(position) );
    }

}
}

Solution 3

Same solution:

private int m_intSpinnerInitiCount = 0;
private static final int NO_OF_EVENTS = 1;

...

m_spnTemplates.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parentView, 
                    View selectedItemView, int position, long id) { 

                //trying to avoid undesired spinner selection changed event, a known problem
                    if (m_intSpinnerInitiCount < NO_OF_EVENTS) {
                        m_intSpinnerInitiCount++;
                    } else {                
                        //YOUR CODE HERE
                    }                           
            }

Solution 4

I ran into this problem yesterday with an OnCheckedChangedListener. I ended up adding a boolean instance variable initialized to true inside of my adapter class with an accessor method isListenerEnabled(). I then set the variable to false in my layout code and set it to true again at the end of the layout code. In my listener, I inspect the value of the variable to decide whether to execute the listener code or not.

Solution 5

You can set your variable back to false everytime on onPause is called. As for when to set it to true, you could do this for the first motion/key/trackball event after onResume.

Share:
31,866

Related videos on Youtube

David
Author by

David

Updated on November 15, 2020

Comments

  • David
    David almost 3 years

    Possible Duplicate:
    Android Spinner OnItemSelected Called Erroneously (without user action on opening spinner)

    Does anyone know how to prevent the onItemSelected() (OnItemSelectedListener interface) method from running when the layout is instantiated? I need to know if there is a way to do this because I want to keep how I instantiate my layout separate from this listener.

    I have tried creating an if statement initially set to false around all the code inside of the overridden method, but there is no way of knowing when to set it to true because the overridden method runs after the onCreate(), onStart(), and onResume() methods everytime.

    I have not found any clear cut answers on this. Any clear cut solutions would be greatly appreciated.

    • hendrix
      hendrix almost 11 years
      The way spinner is designed makes me sick... Definitely worst UI control i've ever worked with...
  • David
    David over 12 years
    I appreciate the response, but could you please show a code snippet demonstrating this solution? Also, my layout is defined in an xml file and the onItemSelected() method runs after
  • David
    David over 12 years
    the setContentView() method which makes it harder
  • James
    James over 12 years
    Post your layout code and then I can assist. Without it, a snippet probably wouldn't be too helpful.
  • David
    David over 12 years
    <TableLayout xmlns:android="schemas.android.com/apk/res/android" style="@style/table_layout_port"> <TableRow style="@style/table_row"> <Spinner android:id="@+id/cidr_mask_spinner" style="@style/spinner" android:entries="@array/subnet_mask" /> <Spinner android:id="@+id/cidr_spinner" style="@style/spinner" android:entries="@array/mask_bits" /> </TableRow> </TableLayout>
  • David
    David over 12 years
    The above post only contains part of my layout. Do I need to recreate the layout pro grammatically?
  • James
    James over 12 years
    Do you have the code where you're setting the listener and setting the initial state of the spinners?
  • EeKay
    EeKay over 11 years
    This is a good answer, as well as the boolean variant khr2003 gave for a single view. Looks like the loading of a view layout and the items executes the itemselected. I find this to be a bug since the actionword selected indicates user interaction and not initialisation setup.
  • IAmGroot
    IAmGroot over 11 years
    Thanks. This fixed a silly problem. :)
  • Jakob
    Jakob almost 11 years
    Why do I get an error on this line: mSpinner.setCallbackDuringFling(false); saying: The method setCallbackDuringFling(boolean) is undefined for the type Spinner? Please help, After hours I finally thought I had found a fix for this anoying problem.
  • Someone Somewhere
    Someone Somewhere almost 11 years
    Harteg, I check the Spinner class and you're right, the method doesn't exist for that class. The spirit of this solution should still apply, but otherwise you can probably just leave that line of code out.
  • PCoder
    PCoder almost 11 years
    +1 for the answer. Just a comment that variable mSpinnerCount and mSpinnerInitializedCount could be more precise. I was lost a bit by Gallery, though you mentioned Spinner in the brackets :)
  • eskalera
    eskalera almost 9 years
    Thanks! I was going crazy with this thinking I was doing something wrong.
  • Jawnnypoo
    Jawnnypoo almost 9 years
    An alternate solution is to set your onSelectedListener in a posted runnable, ie. spinner.postRunnable(//insert runnable that sets your items selected listener); This way it will place it on the spinner message queue and will run it once the spinner is properly initialized. See more about runnables here: stackoverflow.com/questions/13840007/…
  • Deepak
    Deepak almost 8 years
    This works fine, but user is not able to select the item itself. But did I mistake? in this mGalleryCount=0; I put the count for all items to load in spinner and mGalleryInitializedCount ramains as 0. and Spinner items is not getting selected?

Related