Подтвердить что ты не робот

Spinner onItemВыбранный обратный вызов вызывается дважды после поворота, если выбрана ненулевая позиция

Когда я создаю свою активность, я настраиваю Spinner, назначая ему прослушиватель и начальное значение. Я знаю, что обратный вызов onItemSelected вызывается автоматически во время инициализации приложения. То, что я нахожу странным, заключается в том, что при повороте устройства это происходит дважды, что вызывает некоторые проблемы, которые мне придется обойти. Это означает, что не, если исходный выбор счетчика равен нулю. Я смог изолировать проблему, вот простейшая ее деятельность:

public class MainActivity extends Activity implements OnItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i("Test","Activity onCreate");
    setContentView(R.layout.activity_main);
    ((Spinner)findViewById(R.id.spinner1)).setSelection(2);
    ((Spinner)findViewById(R.id.spinner1)).setOnItemSelectedListener(this);
}
@Override
public void onItemSelected(AdapterView<?> spin, View selview, int pos, long selId)
{
    Log.i("Test","spin:"+spin+" sel:"+selview+" pos:"+pos+" selId:"+selId);
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {}
}

И здесь лог-код отображается, когда приложение запущено, а затем устройство повернуто:

    I/Test( 9881): spin:[email protected] sel:[email protected] pos:2 selId:2
    I/Test( 9881): Activity onCreate
    I/Test( 9881): spin:[email protected] sel:[email protected] pos:2 selId:2
    I/Test( 9881): spin:[email protected] sel:[email protected] pos:2 selId:2

Является ли это ожидаемым поведением? Я что-то пропустил?

4b9b3361

Ответ 1

Удалось найти решение в другом вопросе stackoverflow:

spinner.post(new Runnable() {
    public void run() {
        spinner.setOnItemSelectedListener(listener);
    }
});

Ответ 2

В общем, похоже, что есть много событий, которые вызывают вызов onItemSelected, и сложно отслеживать все из них. Это решение позволяет реагировать только на пользовательские изменения с помощью OnTouchListener.

Создайте свой слушатель для счетчика:

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

}

Добавьте слушателя в счетчик как как OnItemSelectedListener, так и OnTouchListener:

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

Ответ 3

Это то, что я сделал:

Сделайте локальную переменную

Boolean changeSpinner = true;

В SaveInstanceMethod сохраните выбранное положение элемента

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

Затем в созданной активности получите этот int из savedInstanceState и если int is!= 0, то установите логическую переменную на false;

@Override
    public void onActivityCreated(Bundle savedInstanceState) {

    if (savedInstanceState!=null) {
        if (savedInstanceState.getInt("ItemSelect")!=0) {
           changeSpinner = false;
        }
    }

}

И для последнего из OnItemSelected из spinner сделайте это

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

Итак, первый раз, когда вызывается, не собирается ничего делать, просто сделайте логическую переменную true, а второй раз будет выполнять код. Возможно, это не лучшее решение, но оно работает.

Ответ 4

При первом запуске onItemSelected параметр view еще не завышен. Второй раз он уже завышен. Решение состоит в том, чтобы обернуть методы внутри onItemSelected с помощью if (view != null).

@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
    if (view != null) { 
        //do things here

    }
}

Ответ 5

Просто используйте setSelection (#, false) перед установкой слушателя:

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    spinner.setSelection(2, false);
    spinner.setOnItemSelectedListener(this);
}

Ключ - это второй параметр, который говорит о том, что он не анимирует переход, и немедленно выполняет действие, а затем предотвращает двойное срабатывание onItemSelected при вызове onCreate.

Ответ 6

Попробуйте следующее:

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

Ответ 7

Вы можете просто вызвать setSelection, как только вы знаете, список элементов и позицию, которую нужно выбрать, таким образом вы избегаете onItemSelected, который вызывается дважды.

Я создал статью о том, что, на мой взгляд, лучший подход Как избежать onItemSelected, который будет вызываться дважды в Spinners