Ответ 1
У меня есть более легкое, и я думаю, лучшее решение. Поскольку мне пришлось обновлять прядильщики даже после инициализации, это более общий подход. Пожалуйста, обратитесь к принятому ответу:
Просто интересно, как вы справляетесь со следующей проблемой: результат вычисляется в зависимости от выбранных элементов двух прядильщиков. Чтобы обрабатывать элементы пользовательского интерфейса, то есть пользователь выбирает новый элемент в одном из прядильщиков, я устанавливаю прослушиватель, используя setOnItemSelectedListener
для счетчика в моем методе onCreate()
активности.
Теперь: это работает, конечно, прекрасно. Работа слушателя - это запуск нового вычисления результата.
Проблема: потому что я перехватываю onPause()
onResume()
для сохранения/восстановления последнего состояния, у меня есть метод, который устанавливает выбранный элемент этих двух прядильщиков программно, как здесь:
startSpinner.setSelection(pStart);
destSpinner.setSelection(pDest);
Эти два вызова также вызовут слушателей! Мой метод расчета для результата плюс уведомление о новом наборе результатов вызывается здесь дважды!
Тупой прямой подход для этого состоит в том, чтобы иметь булевскую переменную отключение независимо от того, что делает слушатель внутри, установив ее перед установкой выбранных элементов и последующей перезагрузкой. Хорошо. Но есть ли лучший способ?
Я не хочу, чтобы слушатели вызывались по коду - действия, только по действиям пользователя!: - (
Как вы это делаете? Спасибо!
У меня есть более легкое, и я думаю, лучшее решение. Поскольку мне пришлось обновлять прядильщики даже после инициализации, это более общий подход. Пожалуйста, обратитесь к принятому ответу:
Чистое решение, на мой взгляд, для различения программных и пользовательских изменений заключается в следующем:
Создайте свой слушатель для счетчика как как OnTouchListener, так и OnItemSelectedListener
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;
}
}
}
Добавьте слушателя в регистр счетчика для обоих типов событий
SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);
Таким образом, любые непредвиденные вызовы вашему методу обработчика из-за инициализации или повторной инициализации будут проигнорированы.
Хорошо, я начал работать так, как хочу.
То, что нужно понять здесь (и я не писал, когда писал этот вопрос...), заключается в том, что все в Android работает в одном потоке - поток пользовательского интерфейса.
Значение: даже если вы устанавливаете значения Spinner здесь и там: они обновляются только (визуально) и, их слушатели называются после всеми методами, которые вы сейчас используете (например, onCreate
, onResume
или что-то еще).
Это позволяет:
currentPos1
, currentPos2
)onItemSelectedListener()
вызывают метод типа refreshMyResult()
или что-то еще.Метод refreshMyResult()
выглядит следующим образом:
int newPos1 = mySpinner1.getSelectedItemPosition();
int newPos2 = mySpinner2.getSelectedItemPosition();
// only do something if update is not done yet
if (newPos1 != currentPos1 || newPos2 != currentPos2) {
currentPos1 = newPos1;
currentPos2 = newPos2;
// do whatever has to be done to update things!
}
Потому что слушатели будут вызываться позже - и к тому времени уже сохраненная память в currentPos уже обновлена - ничего не произойдет, и никакого лишнего обновления ничего не произойдет. Когда пользователь выбирает новое значение в одном из прядильщиков, хорошо - обновление будет выполнено соответствующим образом.
Что это!: -)
Ahh - еще одно: ответ на мой вопрос: Нет. Слушатели не могут быть отключены (легко) и будут вызываться всякий раз, когда изменяется значение.
Очень легко вы можете вызвать метод Spinner.setSelection(int position, boolean animate)
с помощью false
, чтобы слушатели не реагировали на изменения.
Spinner.setSelection(int position, boolean animate) запускает слушателя на 4.3
Я создал библиотеку, которая помогает всем, что нет необходимости вызывать элемент onClick action в Spinner Например:
spinner.setSelection(withAction,position);
где withAction - это булев флаг, используемый для вызова или не действия элемента
Ссылка на Github: https://github.com/scijoker/spinner2
Добавьте OnItemSelectedListener
для каждого счетчика после того, как вы установили любое предыдущее значение в onResume
.
Когда используется Spinner.setSelection(position), он всегда активирует setOnItemSelectedListener()
Чтобы не запускать код дважды, я использую это решение:
private mIsSpinnerFirstCall=true;
...
Spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//If a new value is selected (avoid activating on setSelection())
if(!mIsSpinnerFirstCall) {
// Your code goes gere
}
mIsSpinnerFirstCall = false;
}
public void onNothingSelected(AdapterView<?> arg0) {
}
});
Это решение действительно, когда вы уверены, что мы использовали Spinner.setSelection(position). Кроме того, важно установить mIsSpinnerFirstCall = true каждый раз перед использованием Spinner.setSelection(position)
Boolean check = false;
holder.filters.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
check = true;
return false;
}
});
holder.filters.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
@Override
public void onItemSelected(AdapterView<?> parent, View arg1, int position, long id)
{
flag = filterids.get(position);
if(check)
{
check = false;
new Applyfilters().execute(flag,"3");
}else{
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0)
{
// TODO Auto-generated method stub
}
});