Как отключить onItemSelectedListener для вызова при настройке выбранного элемента по коду

Просто интересно, как вы справляетесь со следующей проблемой: результат вычисляется в зависимости от выбранных элементов двух прядильщиков. Чтобы обрабатывать элементы пользовательского интерфейса, то есть пользователь выбирает новый элемент в одном из прядильщиков, я устанавливаю прослушиватель, используя setOnItemSelectedListener для счетчика в моем методе onCreate() активности.

Теперь: это работает, конечно, прекрасно. Работа слушателя - это запуск нового вычисления результата.

Проблема: потому что я перехватываю onPause() onResume() для сохранения/восстановления последнего состояния, у меня есть метод, который устанавливает выбранный элемент этих двух прядильщиков программно, как здесь:

startSpinner.setSelection(pStart);
destSpinner.setSelection(pDest);

Эти два вызова также вызовут слушателей! Мой метод расчета для результата плюс уведомление о новом наборе результатов вызывается здесь дважды!

Тупой прямой подход для этого состоит в том, чтобы иметь булевскую переменную отключение независимо от того, что делает слушатель внутри, установив ее перед установкой выбранных элементов и последующей перезагрузкой. Хорошо. Но есть ли лучший способ?

Я не хочу, чтобы слушатели вызывались по коду - действия, только по действиям пользователя!: - (

Как вы это делаете? Спасибо!

Ответ 1

У меня есть более легкое, и я думаю, лучшее решение. Поскольку мне пришлось обновлять прядильщики даже после инициализации, это более общий подход. Пожалуйста, обратитесь к принятому ответу:

Нежелательные onItemВыбранные вызовы

Ответ 2

Чистое решение, на мой взгляд, для различения программных и пользовательских изменений заключается в следующем:

Создайте свой слушатель для счетчика как как 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);

Таким образом, любые непредвиденные вызовы вашему методу обработчика из-за инициализации или повторной инициализации будут проигнорированы.

Ответ 3

Хорошо, я начал работать так, как хочу.

То, что нужно понять здесь (и я не писал, когда писал этот вопрос...), заключается в том, что все в 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 - еще одно: ответ на мой вопрос: Нет. Слушатели не могут быть отключены (легко) и будут вызываться всякий раз, когда изменяется значение.

Ответ 4

Очень легко вы можете вызвать метод Spinner.setSelection(int position, boolean animate) с помощью false, чтобы слушатели не реагировали на изменения.

Ответ 5

Spinner.setSelection(int position, boolean animate) запускает слушателя на 4.3

Ответ 6

Я создал библиотеку, которая помогает всем, что нет необходимости вызывать элемент onClick action в Spinner Например:

spinner.setSelection(withAction,position);

где withAction - это булев флаг, используемый для вызова или не действия элемента

Ссылка на Github: https://github.com/scijoker/spinner2

Ответ 7

Добавьте OnItemSelectedListener для каждого счетчика после того, как вы установили любое предыдущее значение в onResume.

Ответ 8

Когда используется 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)

Ответ 9

Сначала добавьте логические значения для остановки вызова прослушивателя счетчика

  Boolean check = false;

Затем вы добавляете на сенсорный прослушиватель и на элементе click Listener. Как ниже код

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

Простая работа для остановки многократного вызова сервера.