Как отключить onItemSelectedListener для вызова при настройке выбранного элемента по коду
просто интересно, как вы справляетесь со следующей проблемой: результат рассчитывается в зависимости от выбранных элементов двух прядильщиков. Для обработки пользовательского интерфейса, т. е. пользователь выбирает новый элемент в одном из блесен, я устанавливаю прослушиватель с помощью setOnItemSelectedListener
для спиннера в my onCreate()
метод действия.
теперь: это работает, конечно, хорошо. Работа слушателя заключается в том, чтобы вызвать новый расчет результата.
проблема: потому что я перехватываю onPause()
onResume()
в сохранить/восстановить последнее состояние, у меня есть метод, который наборы эти две блесны' выбранный элемент программно, как здесь:
startSpinner.setSelection(pStart);
destSpinner.setSelection(pDest);
эти два вызова и вызова слушателей! Мой метод расчета результата плюс уведомление о новом результирующем наборе вызывается здесь дважды!
глупым прямым подходом для этого было бы иметь булеву переменную отключение что бы слушатель ни делал внутри, установите его перед установкой выбранного элементы и сброс его впоследствии. Окей. Но есть ли лучший способ??
Я не хочу, чтобы слушатели вызывались действиями кода, только действиями пользователя! :-(
как вы это делаете? Спасибо!
11 ответов
У меня есть более простое, и я думаю, лучшее решение. Поскольку мне пришлось обновлять блесны даже после инициализации, это более общий подход. Пожалуйста, обратитесь к принятому ответу:
более чистое решение, на мой взгляд, для различения программных и пользовательских изменений является следующим:
создайте своего слушателя для spinner как 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()
или что-то еще. - при программной установке позиций установите блесны и вызовите свой собственный метод обновления вручную сразу после этого.
The 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 уже обновлена-ничего не произойдет и не произойдет ненужного обновления чего-либо еще. Когда пользователь выбирает новое значение в одном из блесен, ну-обновление будет выполнено соответствующим образом!
вот именно! :-)
Ахх-еще одно: ответ на мой вопрос: нет. Прослушиватели не могут быть отключены (легко) и будут вызываться при изменении значения.
очень легко вы можете вызвать Spinner.setSelection(int position, boolean animate)
метод false
таким образом, слушатели не будут реагировать на изменение.
Я создал библиотеку, которая помогает для всех, что нет необходимости вызывать элемент onClick action в Spinner Например:
spinner.setSelection(withAction,position);
где withAction-логический флаг, используемый для вызова или не действия элемента
ссылка на Github: https://github.com/scijoker/spinner2
Сначала добавьте логические значения для остановки вызова Spinner listener
Boolean check = false;
затем вы добавляете на сенсорный прослушиватель и на пункт нажмите прослушиватель, как показано ниже code
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
}
});
его простая работа хороша для остановки вызова сервера несколько раз.
добавить OnItemSelectedListener
для каждой блесны после вы установили любое предыдущее значение в onResume
.
Когда Блесны.используется setSelection (позиция), он всегда активирует 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 (позиция) us используется. Кроме того, важно установить mIsSpinnerFirstCall=true каждый раз перед использованием Spinner.setSelection (позиция)
This following method will help you to stop invoking automatically the selection listener
yourspinnerobj.post(new Runnable() {
@Override
public void run() {
yourspinnerobj.setOnItemSelectedListener(yourspinnerlistener);
}
});
мое решение очень легко. Сначала инициализируйте глобальную логическую переменную.
boolean shouldWork = true;
затем используйте ниже код в методе onCreate ().
Spinner spinner = findViewById(R.id.spinner);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView adapter, View v, int i, long lng) {
if (shouldWork) {
// Do your actions here
}
else
shouldWork = true;
}
public void onNothingSelected(AdapterView<?> parentView) {
}
});
Теперь вы можете использовать метод setSelection в everwhere без вызова метода onItemSelected () с помощью кода ниже.
shouldWork = false;
spinner.setSelection(0);