2010-10-12 4 views
5

Mam Androida ListView, którego elementy mają pole wyboru.CheckBox zmienia wartość dwukrotnie

Pole wyboru jest domyślnie zaznaczone. Po usunięciu zaznaczenia należy go usunąć z listy.

Problemem jest to, że onCheckedChanged jest zwolniony dwa razy: kiedy dotknij pole wyboru, aby je odznaczyć (z isCheckedfalse) i po tym, jak usunąć element (z isCheckedtrue).

to odpowiedni kod mojego ArrayAdapter:

public View getView(final int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 
    if (convertView == null) { 
     convertView = mInflater.inflate(R.layout.item, parent, false); 
     holder = new ViewHolder(); 
     holder.check = (CheckBox) convertView.findViewById(R.id.check); 
     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 
    final Object item = this.getItem(position); 
    holder.check.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() { 
     @Override 
     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
      if (!isChecked) { 
       remove(item); // This somehow calls onCheckedChanged again 
      } 
     } 
    }); 
    return convertView; 
} 

Co robię źle?

+0

Co robi metoda 'remove()', ponieważ nie jest to metoda na liście 'ListAdapter'? – CommonsWare

+0

Używam ArrayAdapter. Zgodnie z kodem źródłowym Androida metoda remove usuwa element z tablicy i informuje, że dane zostały zmienione. – hpique

Odpowiedz

0

Występuje ten sam problem.

Po kilku badaniach dowiedziałem się, że podobne zachowanie występuje w RadioGroup dla setCheckChangeListener.

Oznaczanie powoduje, że wszystko działa, wygląda na błąd.

Moje obejście polegało na ustawianiu znacznika na wartość zerową na końcu słuchacza. To działało dla mnie.

private OnCheckedChangeListener checkBoxitemClickListener = new OnCheckedChangeListener() { 

    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 


     if(isChecked) 
     {    
      //do smth 
     }else 
     { 
      //do smth 
     } 

     buttonView.setTag(null);       
    } 
}; 

Jeśli trzeba po zaktualizować ListView, nie zapomnij, aby zadzwonić „notifyDataSetChanged” na adapterze.

Cheers

5

I napotkał ten sam problem, wydaje się być to bug Android dwukrotnie wykonanie metody onCheckChanged.

Moje rozwiązanie: implementuj onClickListener, zamiast onCheckedChangedListener.

coś takiego:

private final class CheckUpdateListener implements OnClickListener { 

    private Group parent; 
    private boolean isChecked; 

    private CheckUpdateListener(Group parent) { 

     this.parent = parent; 

    } 

    @Override 
    public void onClick(View box) { 
     this.isChecked = !parent.isChecked(); 

     parent.setChecked(isChecked); 

     notifyDataSetChanged(); 

    } 

} 
+0

Tak, uważam, że słuchanie funkcji onCheckedChange jest przesadą, a nie jest właściwe w większości przypadków. Podstawowym problemem jednak dla mnie było uzyskanie właściwej perspektywy, tj. Że Widok nie jest taki sam jak obiekt danych, który jest oglądany. – rwst

2

miałem podobny problem i po prostu rozwiązać go właściwie bez konieczności unikać zamierzonego OnCheckedChangeListener.

Problem Code

holder.someCheckBox.setChecked(false); 
holder.someCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 
    @Override 
    public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { 
     ... 
    } 
}); 

Uwaga ustawić status wyboru przed ustawić słuchacza, to było zapobiec słuchacza od wypalania na stworzeniu.

Ale słuchacz rozpoczął wypalanie zdarzenia kontrolnego dokładnie dwa razy tylko po tym, jak adapter został zmuszony do ponownego utworzenia lub przy użyciu notifyDataSetChanged.

Rozwiązanie

Wyczyść słuchacz przed ustawiania stanu wyboru, nawet podczas tworzenia tutaj.

holder.someCheckBox.setOnCheckedChangeListener(null); 
holder.someCheckBox.setChecked(false); 
holder.someCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 
    @Override 
    public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { 
     ... 
    } 
}); 

Teraz wszystkie pozostałe słuchacze nie zostaną uruchomione podczas ustawiania początkowej wartości pola wyboru.