onCheckedChanged вызывается автоматически

У меня есть переключатель в recyclerview, и данные отображаются в recyclerview после извлечения данных из БД. Когда открывается recyclerview, я читаю DB, и если поле в DB имеет значение «Y», я включаю переключатель или отключаю его. Теперь проблема заключается в том, что также вызывается прослушиватель onCheckedchanged, я хочу, чтобы onCheckedChanged вызывался только тогда, когда пользователь устанавливает переключатель вручную.

При открытии выполняется Reclerview ниже:

holder.enabledisable.setChecked(messengerRecord.get_is_valid().equalsIgnoreCase("Y"));

ViewHolder класс:

public class viewHolder extends RecyclerView.ViewHolder implements CompoundButton.OnCheckedChangeListener{
public SwitchCompat enabledisable;
 public viewHolder(View v) {
            enabledisable = (SwitchCompat) v.findViewById(R.id.enabledisable);
            enabledisable.setOnCheckedChangeListener(this);
...................................
...................................

OncheckedChanged, который вызывается при открытии recyclerView:

@Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            Log.v("ranjith","called oncheckedchanged");
            MessengerRecord rec;
            rec = dbHelper.getRecord(descview.getText().toString());
            switch (buttonView.getId()) {
                case R.id.enabledisable:
                    if (isChecked) {
                        rec.set_is_valid("Y");
                        dbHelper.updateRecord(rec);
                     }
}

В файле макета:

<android.support.v7.widget.SwitchCompat
    android:layout_marginRight="16dp"
    android:layout_marginEnd="16dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:focusable="false"
    android:id="@+id/enabledisable"
    android:layout_alignRight="@+id/textview_to"
    android:layout_alignEnd="@+id/textview_to"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"/>

person Psypher    schedule 24.12.2014    source источник


Ответы (8)


Странно, что у всех нас есть эта проблема, но нет официального ответа Google на эту простую проблему.

НАИБОЛЕЕ просто проверить:

buttonView.isPressed()

Если true, означает, что пользователь щелкнул представление.

Никаких глобальных переменных не требуется.

Надеюсь это поможет.

person Sulfkain    schedule 29.01.2015
comment
Это определенно работает. Но есть ли какое-нибудь событие, если пользователь сдвигает переключатель? В этом случае, если используется скользящий переключатель, это не работает. - person dhun; 07.08.2015
comment
Спасибо за это простое, но отличное решение. Это также можно использовать с RadioButton. Для RadioGroup я написал этот ответ. - person Sufian; 06.02.2016
comment
Спасибо @Surfian за упоминание :), я рад, что это работает и для RadioButton - person Sulfkain; 12.02.2016
comment
решение не сработает, если вы очень быстро проведете по переключателю. Глупый гугл - person DàChún; 17.05.2016
comment
Вы можете справиться вручную, реализуя OnClickListener и проверяя с помощью метода isChecked () SwitchCompat, не требуя использования onCheckedChangeListener. - person mr.boyfox; 06.04.2018

В итоге я использовал этот подкласс SwitchCompat, чтобы избежать этой проблемы. Таким образом, мне не нужен шаблонный код, в котором я использую этот класс. Всякий раз, когда вам нужно изменить отмеченный флажок без запуска слушателя, используйте setCheckedSilent вместо setChecked:

import android.content.Context;
import android.os.Parcelable;
import android.support.v7.widget.SwitchCompat;
import android.util.AttributeSet;

/**
 * Created by emanuel on 30/5/16.
 */
public class Switch extends SwitchCompat {

    private OnCheckedChangeListener listener;

    public Switch(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
        this.listener = listener;
        super.setOnCheckedChangeListener(listener);
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        super.setOnCheckedChangeListener(null);
        super.onRestoreInstanceState(state);
        super.setOnCheckedChangeListener(listener);
    }

    public void setCheckedSilent(boolean checked) {
        super.setOnCheckedChangeListener(null);
        super.setChecked(checked);
        super.setOnCheckedChangeListener(listener);
    }
}

onRestoreInstanceState также запускал прослушивание, когда он установлен в методе onViewCreated, и вы возвращаетесь к предыдущему фрагменту. Надеюсь, это сработает для вас!

person Emanuel Andrada    schedule 30.05.2016

Попробуй это

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

        if (buttonView.isPressed()) {
          ... //returns true, if user clicks the switch button        
        }}
person Shyam Kumar    schedule 28.06.2018
comment
Это не сработает, если смахивание выполняется очень быстро. - person Manuel; 17.12.2019
comment
Был разработчиком Android более 10 лет, никогда не знал об этом трюке, спасибо! - person Boy; 27.02.2021

Поскольку RecyclerView повторяет просмотры, ранее присоединенный OnCheckedChangeListener может быть запущен при установке проверенного значения для Switch нового элемента.

При привязке новых данных к элементу:

   switch.setOnCheckedChangeListener(null) // remove any existing listener from recycled view
   switch.isChecked = [true/false] // will no longer trigger any callback to listener
   switch.setOnCheckedChangeListener { btnView, isChecked ->
       // do exiting stuff
   }
person jayeffkay    schedule 15.01.2021
comment
Большое спасибо за то, что разместили это. У меня несколько Switch просмотров в Recyclerview, и у меня была именно эта проблема. Удаление всех существующих слушателей в onBind() сначала решило мои проблемы. - person user2350644; 07.07.2021

Это работает для меня:

 boolean selected = preferences.isChecked();
        yourCheckBox.setOnCheckedChangeListener(new 
            CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, 
            boolean isChecked) {
                    if (buttonView.isPressed()) {
               preferences.setChecked(isChecked);
                    } else {
                        yourCheckBox.setChecked(selected);
                    }
                }
            });
person Dima Zatolokin    schedule 05.04.2018
comment
Это не сработает, если смахивание выполняется очень быстро. - person Manuel; 17.12.2019

используйте глобальную логическую переменную и при чтении данных из БД установите для нее значение «истина», а после проверки (если) в onCheckChange снова установите значение «ложь». вначале метод onCheckChange проверяет, является ли эта переменная ложной, выполнить коды, иначе вернуть (значение по умолчанию этой переменной должно быть ложным);

@Override
   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
     if(!isSourceDB){ 

       Log.v("ranjith","called oncheckedchanged");
        MessengerRecord rec;
        rec = dbHelper.getRecord(descview.getText().toString());
        switch (buttonView.getId()) {
            case R.id.enabledisable:
                if (isChecked) {
                    rec.set_is_valid("Y");
                    dbHelper.updateRecord(rec);

          }
    }//end if
  isSourceDB = false; }// end oncheckedchange
person mk72    schedule 24.12.2014
comment
Кажется, это работа. Я искал функциональность в Android, которая вызывает oncheckedchanged только при нажатии пользователем (т.е. фокус получен). Но это работает. Голосуйте за меня. - person Psypher; 26.12.2014
comment
@Ranjith: при нажатии на Switch вызывается первый метод toggle (), а в методе toggle вызывается метод setchecked (). поэтому вы должны вставить приведенные выше коды в метод переключения, а не на checkchanged. кстати, если вы хотите просто написать в onCheckChange (), вы должны написать метод, который изменяет только состояние переключателя GUI и вызывает его при чтении данных из БД. - person mk72; 27.12.2014

Я столкнулся с той же проблемой на экране ViewPager для фрагментов. Когда мы переключаемся между фрагментами, onCheckedChanged Listener вызывается снова и снова.

Если кто-то все еще ищет эту проблему, попробуйте.

@Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

            if (buttonView.isInTouchMode()) {
              ... //Your code will come here.         
            }
}
person Arthur    schedule 09.04.2015

Разработчики Kotlin:

    checkboxXYZ.setOnCheckedChangeListener { btnView, isChecked ->
        if (btnView.isPressed) {

        }
    }
person Kishan Solanki    schedule 14.08.2020