Ответ 1
Удалось найти решение в другом вопросе stackoverflow:
spinner.post(new Runnable() {
public void run() {
spinner.setOnItemSelectedListener(listener);
}
});
Когда я создаю свою активность, я настраиваю 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
Является ли это ожидаемым поведением? Я что-то пропустил?
Удалось найти решение в другом вопросе stackoverflow:
spinner.post(new Runnable() {
public void run() {
spinner.setOnItemSelectedListener(listener);
}
});
В общем, похоже, что есть много событий, которые вызывают вызов 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);
Это то, что я сделал:
Сделайте локальную переменную
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, а второй раз будет выполнять код. Возможно, это не лучшее решение, но оно работает.
При первом запуске onItemSelected
параметр view
еще не завышен. Второй раз он уже завышен. Решение состоит в том, чтобы обернуть методы внутри onItemSelected
с помощью if (view != null)
.
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (view != null) {
//do things here
}
}
Просто используйте setSelection (#, false) перед установкой слушателя:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
spinner.setSelection(2, false);
spinner.setOnItemSelectedListener(this);
}
Ключ - это второй параметр, который говорит о том, что он не анимирует переход, и немедленно выполняет действие, а затем предотвращает двойное срабатывание onItemSelected при вызове onCreate.
Попробуйте следующее:
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;
}
Вы можете просто вызвать setSelection
, как только вы знаете, список элементов и позицию, которую нужно выбрать, таким образом вы избегаете onItemSelected
, который вызывается дважды.
Я создал статью о том, что, на мой взгляд, лучший подход Как избежать onItemSelected, который будет вызываться дважды в Spinners