Vista de lista de Android con ViewHolder

Tengo un problema. Estoy intentando cambiar un ícono en mi lista de lista después de haber hecho clic en él. Funciona correctamente, aunque no se modifican solo los icons que se presionan, sino también los que no se muestran. Por ejemplo, si hago clic en el icono en el primer elemento de la vista de lista, también cambia el quinto icono. Este comportamiento se repite para todos los elementos siguientes (cada cinco elementos de la vista de lista). Este es mi método getView:

public class AlphabeticalAdapter extends ArrayAdapter { int layoutResourceId; private final Context context; private List data; private ProgressDialog mProgressDialog; private ImageView downloadImageButton; public AlphabeticalAdapter(Context context, int resource, List data){ super(context, resource, data); this.layoutResourceId = resource; this.context = context; this.data = data; } public View getView(int position, View convertView, ViewGroup parent) { // View rowView = convertView; final ViewHolder viewHolder; if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.catalogslist_single_row, parent, false); viewHolder = new ViewHolder(); viewHolder.catlogTitle=(TextView)convertView.findViewById(R.id.txtTitle); viewHolder.icon=(ImageView)convertView.findViewById(R.id.imageView2); viewHolder.downloadImageButton=(ImageView)convertView.findViewById(R.id.downloadImageButton); //downloadImageButton = (ImageView)rowView.findViewById(R.id.downloadImageButton); viewHolder.position = position; viewHolder.downloadImageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { System.out.println("DOWNLOAD PRESSED"); viewHolder.downloadImageButton = (ImageView)v.findViewById(R.id.downloadImageButton); viewHolder.downloadImageButton.setImageResource(R.drawable.icon_ok); viewHolder.downloadImageButton.setTag("downloaded"); //rowView.setTag("downloaded"); } }); convertView.setTag(viewHolder); } else{ viewHolder= (ViewHolder)convertView.getTag(); } viewHolder.catlogTitle.setText(data.get(position)); viewHolder.catlogTitle.setTypeface(regularDin); viewHolder.icon.setImageResource(R.drawable.cata); if(viewHolder.downloadImageButton.getTag() == "downloaded"){ downloadImageButton = (ImageView)convertView.findViewById(R.id.downloadImageButton); downloadImageButton.setImageResource(R.drawable.icon_ok); } else{ downloadImageButton = (ImageView)convertView.findViewById(R.id.downloadImageButton); downloadImageButton.setImageResource(R.drawable.icon_download); } viewHolder.position = position; return convertView; } //close getView 

Y esta es mi clase ViewHolder:

  static class ViewHolder{ ImageView downloadImageButton; TextView catlogTitle; ImageView icon; int position; } 

Cambia tu código a continuación. Creo que te estás perdiendo eso.

 public class AlphabeticalAdapter extends ArrayAdapter { int layoutResourceId; private final Context context; private List data; private List tags; private ProgressDialog mProgressDialog; private ImageView downloadImageButton; public AlphabeticalAdapter(Context context, int resource, List data) { super(context, resource, data); this.layoutResourceId = resource; this.context = context; this.data = data; tags = new ArrayList(); int size = data.size(); for (int i = 0; i < size; i++) { tags.add("tag"); } } static class ViewHolder { ImageView downloadImageButton; TextView catlogTitle; ImageView icon; int position; } public View getView(final int position, View convertView, ViewGroup parent) { // View rowView = convertView; final ViewHolder viewHolder; if (convertView == null) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // convertView = inflater.inflate(R.layout.catalogslist_single_row, // parent, false); viewHolder = new ViewHolder(); viewHolder.position = position; viewHolder.downloadImageButton .setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { System.out.println("DOWNLOAD PRESSED"); viewHolder.downloadImageButton.setTag("downloaded"); tags.add(position, "downloaded"); } }); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.catlogTitle.setText(data.get(position)); viewHolder.catlogTitle.setTypeface(regularDin); viewHolder.icon.setImageResource(R.drawable.cata); if (tags.get(position) == "downloaded") { downloadImageButton.setImageResource(R.drawable.icon_ok); } else { downloadImageButton.setImageResource(R.drawable.icon_download); } viewHolder.position = position; return convertView; } // close getView } 

Hay tantos convertViews como tantas filas visibles al mismo tiempo en su ListView (el sistema lo reutiliza). Entonces realmente tienes 5 convertView , y por eso tienes 5 ImageView para los íconos. El problema es que usa esa etiqueta de ImageView para almacenar la información “descargada”. Eso es 5 estados, y es por eso que ves cada quinta fila descargada mientras te desplazas por la lista.

Supongo que ahora ves que no funcionará. Necesita almacenar el estado descargado para cada elemento, por lo que debe cambiar la List subyacente List a List , donde ListItem puede almacenar el estado descargado para la fila real.

Después de eso, todo lo que tienes que hacer es actualizar ImageView de getView() en getView() ) para mostrar el ícono correcto.

Cambia tu código así Agregue un cheque nulo con convertView antes de su locking try.

  final MenuItem menuItem = getItem(position); View view = convertView; final ViewHolder viewHolder; if (convertView == null) { LayoutInflater inflater; inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.menu_item, parent, false); viewHolder = new ViewHolder(); // viewHolder.half = (TextView) view.findViewById(R.id.half); viewHolder.name = (TextView) view.findViewById(R.id.name); viewHolder.description = (TextView) view.findViewById(R.id.description); viewHolder.price = (TextView) view.findViewById(R.id.price); viewHolder.add = (Button) view.findViewById(R.id.add); viewHolder.selectedView = view.findViewById(R.id.selectedView); viewHolder.remove = (Button) view.findViewById(R.id.remove); viewHolder.total = (TextView) view.findViewById(R.id.itemTotal); viewHolder.quantity = (TextView) view.findViewById(R.id.quantity); view.setTag(viewHolder); }else{ viewHolder= (ViewHolder)convertView.getTag(); } 
 public class AndroidListViewActivity extends ListActivity { private ListView listView; private String names[] = { "HV CAPACITOR", "LV CAPACITORCSS", }; private String desc[] = { "The Powerful Hypter Text Markup Language 5", "Cascading Style Sheets", }; private Integer imageid[] = { R.drawable.hv_capacitor, R.drawable.lv_capacitor, }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.capacitor_layout); // storing string resources into Array String[] product_name = getResources().getStringArray(R.array.product_name); // Binding Array to ListAdapter this.setListAdapter(new ArrayAdapter(this, R.layout.list_item, R.id.label, product_name)); ListView lv = getListView(); // listening to single list item on click lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { // selected item String product = ((TextView) view).getText().toString(); // Launching new Activity on selecting single List Item Intent i = new Intent(getApplicationContext(), SingleListItem.class); // sending data to new activity i.putExtra("product", product); startActivity(i); } }); CapacitorList capacitorList = new CapacitorList(this, names, desc, imageid); listView = (ListView) findViewById(R.id.listView); listView.setAdapter(capacitorList); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { // Launching new Activity on selecting single List Item Intent i = new Intent(getApplicationContext(), CapacitorList.class); // sending data to new activity // startActivity(i); @Override public void onItemClick(AdapterView adapterView, View view, int i, long l) { Toast.makeText(getApplicationContext(), "You Clicked " + names[i], Toast.LENGTH_SHORT).show(); } }); } @Override public boolean onCreateOptionsMenu (Menu menu){ // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected (MenuItem item){ // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }