Estado de la checkbox ListView Viewholder

Tengo algunos problemas con mi adaptador personalizado ListView (y su recientemente implementado viewHolder). Tengo un ListView con una checkbox para cada elemento (nada nuevo aquí). El problema es que si hay más de 9 elementos en mi lista, cuando marque la primera checkbox, la décima será automáticamente marcada (lo mismo para la segunda que para la undécima) como si hubiera un oyente para ambos elementos (y yo creo que es el caso de alguna manera).

Leí sobre el problema de la posición con listView, el reciclaje de vistas y la manera de ViewHolder de resolverlo aquí: ¿Cómo puedo hacer que mi ArrayAdapter siga el patrón ViewHolder?

Pero probablemente hice algo mal porque no está funcionando …

public class PresenceListAdapter extends SimpleAdapter { private LayoutInflater inflater; private List ids; private List statuts; public PresenceListAdapter (Context context, List<? extends Map> data, int resource, String[] from, int[] to, List ids, List statuts) { super (context, data, resource, from, to); inflater = LayoutInflater.from (context); this.ids = ids; this.statuts= statuts; } @Override public Object getItem (int position) { return super.getItem (position); } @Override public View getView (int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = inflater.inflate (R.layout.list_text_checkbox, null); holder = new ViewHolder(); holder.btn = (Button) convertView.findViewById(R.id.btnRetard); holder.check = (CheckBox) convertView.findViewById(R.id.checkPresent); if (statuts.get(position).equals("P")) { Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_online); holder.btn.setCompoundDrawablesWithIntrinsicBounds( img, null, null, null ); holder.btn.setEnabled(true); holder.check.setChecked(true); } else if(statuts.get(position).equals("R")) { Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_away); holder.btn.setCompoundDrawablesWithIntrinsicBounds( img, null, null, null ); holder.btn.setEnabled(true); holder.check.setChecked(true); } else { Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_invisible); holder.btn.setCompoundDrawablesWithIntrinsicBounds( img, null, null, null ); holder.check.setChecked(false); } convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } int id = ids.get(position); if(id != 0) { holder.check.setTag(id); holder.btn.setTag(id); } return super.getView (position, convertView, parent); } static class ViewHolder { Button btn; CheckBox check; } 

Y mi oyente: public void changerPresent (Ver v) {

  CheckBox checkPresent = (CheckBox) v; int idPersonne = (Integer) checkPresent.getTag(); View parent = (View)v.getParent(); Button btn = (Button) parent.findViewById(R.id.btnRetard); if(checkPresent.isChecked()) { gestion.updatePresence(idPersonne, idSeance, "P"); btn.setEnabled(true); setBtnRetardPresent(btn); } else { gestion.updatePresence(idPersonne, idSeance, "A"); btn.setEnabled(false); setBtnRetardAbsent(btn); } } 

Agradecería cualquier ayuda en este punto, estoy trabajando en esto por horas ahora.

Muchas gracias.

Así es como lo hice funcionar:

Primero, necesita una matriz separada para su estado verificado. Tiene que ser del mismo tamaño que el getCount() su adaptador.

Luego, en su getView, el setOnCheckedChangedListener de su checkbox DEBE PRECEDER sus declaraciones checkbox.setChecked.

ejemplo:

 holder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { isChecked[position] = isChecked; } }); holder.checkBox.setChecked(isChecked[position]); 

Debe establecer el estado de CheckedBox fuera de la inicialización de ViewHolder, como el siguiente código:

 if (convertView == null) { viewHolder = new ViewHolder(); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.checkedBox.setChecked(); 

Por cierto: use SparseBooleanArray en lugar de dos listas para almacenar el estado de CheckedBox.

El problema es debido al hecho de que listview lo recicla

entonces en el método getView( )

  if (convertView == null) { ........ } else { holder = (ViewHolder) convertView.getTag(); } // Uncheck needed boxes here... You need to implement your logic if( 'position' is checked earlier) holder.check.setChecked(true); else holder.check.setChecked(false); 

Debe escribir el código para administrar el estado de la vista si la conversión no es nula, porque es una vista ya usada que puede estar marcada con casillas de verificación.