Spinner's onItemSelected callback called twice after a rotation if non-zero position is selected

后端 未结 8 1038
执念已碎
执念已碎 2021-02-03 20:52

When I create my activity, I setup a Spinner, assigning it a listener and an initial value. I know that the onItemSelected callback is called automatically during a

相关标签:
8条回答
  • 2021-02-03 21:11

    I am updating @Andres Q.'s answer in Kotlin.

    Create an inner class in which you're using Spinner

    inner class SpinnerInteractionListener : AdapterView.OnItemSelectedListener, View.OnTouchListener {
            override fun onNothingSelected(parent: AdapterView<*>?) {
    
            }
    
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                if (userSelect) {
                    //Your selection handling code here
                    userSelect = false
                }
            }
    
            @SuppressLint("ClickableViewAccessibility")
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                userSelect = true
                return false
            }
    
            internal var userSelect = false
        }
    

    Then declare instance variable outside onCreate() as globally like

    lateinit var spinnerInteractionListener: SpinnerInteractionListener
    

    then initialise it inside onCreate() by

    spinnerInteractionListener = SpinnerInteractionListener()
    

    and use it like

    spinnerCategory.onItemSelectedListener = spinnerInteractionListener
    spinnerCategory.setOnTouchListener(spinnerInteractionListener)
    

    here spinnerCategory is Spinner

    0 讨论(0)
  • 2021-02-03 21:13

    You can just call to setSelection once you know have the list of items and the position to be selected, in that way you avoid onItemSelected to be called twice.

    I've created an article about what I think is a better approach How to avoid onItemSelected to be called twice in Spinners

    0 讨论(0)
  • 2021-02-03 21:15

    Managed to find a solution in another stackoverflow question:

    spinner.post(new Runnable() {
        public void run() {
            spinner.setOnItemSelectedListener(listener);
        }
    });
    
    0 讨论(0)
  • 2021-02-03 21:22

    Try this:

    boolean mConfigChange = false;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        mConfigChange = false;
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mainf);
    
        Log.i("SpinnerTest", "Activity onCreate");
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.colors,
                android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        ((Spinner) findViewById(R.id.spin)).setAdapter(adapter);
    
         ((Spinner) findViewById(R.id.spin)).setSelection(2);
        ((Spinner) findViewById(R.id.spin)).setOnItemSelectedListener(this);
    
    }
    
    @Override
    protected void onResume() {
        mConfigChange = true;
        super.onResume();
    }
    
    @Override
    public void onItemSelected(AdapterView<?> spin, View selview, int pos, long selId) {
        if (!mConfigChange)
            Log.i("Test", "spin:" + spin + " sel:" + selview + " pos:" + pos + " selId:" + selId);
        else
            mConfigChange = false;
    }
    
    0 讨论(0)
  • 2021-02-03 21:25

    The first time the onItemSelected runs, the view is not yet inflated. The second time it is already inflated. The solution is to wrap methods inside onItemSelected with if (view != null).

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
        if (view != null) { 
            //do things here
    
        }
    }
    
    0 讨论(0)
  • 2021-02-03 21:26

    This is what i did:

    Do a local variable

    Boolean changeSpinner = true;
    

    On the saveInstanceMethod save the selected item position of the spinner

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("ItemSelect",mySpinner.getSelectedItemPosition());
    }
    

    Then on the activity created get that int from savedInstanceState and if the int is != 0 then set the boolean variable on false;

    @Override
        public void onActivityCreated(Bundle savedInstanceState) {
    
        if (savedInstanceState!=null) {
            if (savedInstanceState.getInt("ItemSelect")!=0) {
               changeSpinner = false;
            }
        }
    
    }
    

    And for last on the OnItemSelected from the spinner do this

    mySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        public void onItemSelected(AdapterView<?> parent,android.view.View v, int position, long id) {
            if (changeSpinner) {
               [...]
            } else {
               changeSpinner= true;
            }
        });
    

    So, the first time when is called is not going to do anything, just make the boolean variable true, and the second time is going to execute the code. Maybe not the best solution but it work.

    0 讨论(0)
提交回复
热议问题