Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android listview using ViewHolder

I have a problem. I'm attempting to change an icon in my listview after it has been clicked. It works correctly although are not modified only the clicked icons but also those who are not displayed. For example if I click the icon in the first item of the listview, also the fifth icon changes. This behaviour is repeated for all the following items (every five items of the listview). This is my getView method:

   public class AlphabeticalAdapter extends ArrayAdapter<String>
   {
       int layoutResourceId; 
       private final Context context;
       private List<String> data;
       private ProgressDialog mProgressDialog;
       private ImageView downloadImageButton;


       public AlphabeticalAdapter(Context context, int resource, List<String> 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 

...

And this is my ViewHolder class:

      static class ViewHolder{
       ImageView downloadImageButton;
       TextView catlogTitle;
       ImageView icon;
       int position;
   }
like image 930
Mark Avatar asked Jul 21 '14 12:07

Mark


People also ask

How do you connect an adapter with ListView write down the codes for it?

Attaching the Adapter to a ListView // Construct the data source ArrayList<User> arrayOfUsers = new ArrayList<User>(); // Create the adapter to convert the array to views UsersAdapter adapter = new UsersAdapter(this, arrayOfUsers); // Attach the adapter to a ListView ListView listView = (ListView) findViewById(R. id.

How do you populate a ListView?

To add rows to a ListView you need to add it to your layout and implement an IListAdapter with methods that the ListView calls to populate itself. Android includes built-in ListActivity and ArrayAdapter classes that you can use without defining any custom layout XML or code.

What is the use of ViewHolder?

A ViewHolder describes an item view and metadata about its place within the RecyclerView. Adapter implementations should subclass ViewHolder and add fields for caching potentially expensive findViewById results.

Is ListView a ViewGroup?

ListView is a ViewGroup that displays a list of vertically scrollable items.


3 Answers

Change your code at below. I think you're missing that.

public class AlphabeticalAdapter extends ArrayAdapter<String> {
    int layoutResourceId;
    private final Context context;
    private List<String> data;
    private List<String> tags;
    private ProgressDialog mProgressDialog;
    private ImageView downloadImageButton;

    public AlphabeticalAdapter(Context context, int resource, List<String> data) {
        super(context, resource, data);
        this.layoutResourceId = resource;
        this.context = context;
        this.data = data;
        tags = new ArrayList<String>();
        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
}
like image 122
Divyang Metaliya Avatar answered Oct 22 '22 02:10

Divyang Metaliya


There are as many convertViews as many row visible in the same time in your ListView (the system reuses it). So you actually have 5 convertView, and because of that you have 5 ImageView for the icons. The problem is that you use those ImageView's tag to store the "downloaded" information. That is 5 state, and that is why you see every fifth row downloaded while you scroll in the list.

I guess now you see that it won't work. You need to store the downloaded state for every item, so you have to change the underlying List<String> to List<ListItem>, where ListItem can store the downloaded state for the actual row.

After that, all you have to do is to update the convertView's ImageView (in getView()) to show the correct icon.

like image 45
kupsef Avatar answered Oct 22 '22 02:10

kupsef


Change your code like this. Add null check with convertView before your try block.

    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(); 
}
like image 1
Rakesh Avatar answered Oct 22 '22 01:10

Rakesh