onCheckedChanged wird automatisch aufgerufen

75

Ich habe einen Schalter in einer Recyclingansicht und Daten werden in der Recyclingansicht angezeigt, nachdem Daten aus der Datenbank abgerufen wurden. Wenn die Recycling-Ansicht geöffnet wird, lese ich DB und wenn ein Feld in DB "Y" ist, aktiviere ich den Switch oder deaktiviere den Switch. Jetzt ist das Problem damit verbunden, dass auch der onCheckedchanged-Listener aufgerufen wird. Ich möchte, dass onCheckedChanged nur aufgerufen wird, wenn der Benutzer den Schalter manuell einstellt.

Beim Öffnen wird die folgende Recycling-Ansicht ausgeführt:

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

ViewHolder-Klasse:

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-Methode, die aufgerufen wird, wenn die recyclerView gerade geöffnet wird:

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

In der Layoutdatei:

<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"/>
Psypher
quelle

Antworten:

251

Es ist seltsam, dass wir alle dieses Problem haben, aber keine offizielle Antwort von Google auf dieses einfache Problem.

Am einfachsten ist es zu überprüfen:

buttonView.isPressed()

Wenn true, bedeutet dies, dass der Benutzer auf die Ansicht geklickt hat.

Keine globalen Variablen erforderlich.

Hoffe das hilft.

Sulfkain
quelle
4
Das funktioniert definitiv. Aber gibt es ein Ereignis, wenn der Benutzer den Schalter drückt? In diesem Fall funktioniert dies nicht, wenn der verwendete Schalter den Schalter verschiebt.
Dhun
Vielen Dank für diese einfache, aber großartige Lösung. Dies kann auch mit verwendet werden RadioButton. Denn RadioGroupich habe diese Antwort geschrieben .
Sufian
Vielen Dank an @Surfian für die Erwähnung :), ich bin froh, dass dies auch für RadioButton
Sulfkain
16
Die Lösung funktioniert nicht, wenn Sie den Switch sehr schnell durchziehen. Dummes Google
DàChún
Sie können manuell vorgehen, indem Sie OnClickListener implementieren und mit der isChecked () -Methode von SwitchCompat prüfen. Die Verwendung von onCheckedChangeListener war nicht erforderlich.
mr.boyfox
13

Ich habe diese Unterklasse von SwitchCompat verwendet, um dieses Problem zu vermeiden. Auf diese Weise benötige ich keinen Boilerplate-Code, in dem ich diese Klasse verwende. Wenn Sie das Häkchen ändern müssen, ohne den Listener auszulösen, verwenden Sie setCheckedSilentanstelle von 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);
    }
}

onRestoreInstanceStatehat auch das Abhören ausgelöst, wenn in der onViewCreatedMethode festgelegt und Sie zu einem vorherigen Fragment zurückkehren. Hoffe es funktioniert bei dir!

Emanuel Andrada
quelle
11

Versuche dies

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

        if (buttonView.isPressed()) {
          ... //returns true, if user clicks the switch button        
        }}
Shyam Kumar
quelle
1
Dies funktioniert nicht, wenn das Wischen sehr schnell erfolgt.
Manuel
2

Das funktioniert bei mir:

 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);
                    }
                }
            });
Dima Zatolokin
quelle
Dies funktioniert nicht, wenn das Wischen sehr schnell erfolgt.
Manuel
0

Verwenden Sie eine globale boolesche Variable. Wenn Sie Daten aus der Datenbank lesen, setzen Sie sie auf "true" und setzen Sie sie nach Prüfung (if) in onCheckChange erneut auf "false". Überprüfen Sie im ersten Teil der onCheckChange-Methode, ob diese Variable falsch ist. Führen Sie die Codes aus. Andernfalls wird zurückgegeben (der Standardwert dieser Variablen muss false sein.).

@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
mk72
quelle
Dies scheint eine Problemumgehung zu sein. Ich suchte nach einer Funktionalität in Android, die nur dann aktiviert wird, wenn der Benutzer darauf klickt (dh der Fokus wird empfangen). Aber es funktioniert. Stimmen Sie von mir ab.
Psypher
@Ranjith: Wenn der Schalter zuerst angeklickt wird, wird die toggle () -Methode aufgerufen und in der toggle-Methode die setchecked () -Methode aufgerufen. Daher sollten Sie die obigen Codes in die Umschaltmethode einfügen, die nicht geändert wurde. Übrigens, wenn Sie nur in onCheckChange () schreiben möchten, sollten Sie eine Methode schreiben, die nur den GUI-Status des Schalters ändert und ihn beim Lesen von Daten aus der Datenbank aufruft.
mk72
0

Ich hatte das gleiche Problem im ViewPager-Bildschirm für Fragmente. Wenn wir zwischen Fragmenten wechseln, wird onCheckedChanged Listener immer wieder aufgerufen.

Wenn noch jemand nach diesem Problem sucht, versuchen Sie es bitte.

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

            if (buttonView.isInTouchMode()) {
              ... //Your code will come here.         
            }
}
Arthur
quelle
0

Kotlin Entwickler:

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

        }
    }
Kishan Solanki
quelle