funambulist
funambulist

Reputation: 51

Selecting a specific checkbox in a long listview checks multiple checkboxes

I have a listview with a checkbox. I click on particular item, the corresponding checkbox gets selected, but it also selects checkboxes repeatedly after every 8-10 rows in the listview. I understand this happens because in android, views for only the screen visible are stored for memory optimization. But I have not been able to overcome this situation. Pls suggest.

public class FBFriendsListAdaptor extends ArrayAdapter<FBFriendItem>{
     private final Context context;
     private static List<FBFriendItem> items;
     private SparseArray<FBFriendItem> checkedItems = new SparseArray<FBFriendItem>();
     ViewHolder holder;

     public FBFriendsListAdaptor(Context context, List<FBFriendItem> items) {
         super(context, R.layout.fb_friend_list, items);
         this.items = items;
         this.context = context;
     }

     @Override
     public FBFriendItem getItem(int position) {
        // TODO Auto-generated method stub
        return items.get(position);
     }

     public View getView(final int position, View convertView, ViewGroup parent) {

         View v = convertView;

         if (v == null) {
             LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             v = vi.inflate(R.layout.fb_friend_list, parent, false);
         }

         holder = new ViewHolder();
         holder.selectFriendCB = (CheckBox)v.findViewById(R.id.selectFriendCB);
         v.setTag(holder);

         v.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                if (checkedItems.get(position) != null){
                    checkedItems.remove(position);
                    holder.selectFriendCB.setChecked(false);
                }
                else {
                    checkedItems.put(position, items.get(position));
                    holder.selectFriendCB.setChecked(true);
                }
            }
         });

         FBFriendItem item = items.get(position);
         TextView firstNameTV = (TextView) v.findViewById(R.id.firstNameTV);
         TextView lastNameTV = (TextView) v.findViewById(R.id.lastNameTV);
         ImageView picIV = (ImageView) v.findViewById(R.id.picIV);
         if (!item.getFbId().isEmpty()) {
             firstNameTV.setText(" " + item.getFirstName());
             lastNameTV.setText(" " + item.getLastName());
             Bitmap image = item.getImage();
             if(image != null) {
                 picIV.setImageBitmap(image);
             }
         }

         return v;
     }

     public SparseArray<FBFriendItem> getCheckedItems(){
         return checkedItems;
     }

     static class ViewHolder {
         CheckBox selectFriendCB;        
     }
}

Upvotes: 2

Views: 1118

Answers (2)

funambulist
funambulist

Reputation: 51

This is how it worked. I added a "boolean selected = false" to the FBFriendItem class. Below is the getView() code inside array adaptor:

public View getView(final int position, View convertView, ViewGroup parent) {

     ViewHolder holder = null;

     View v = convertView;
     if (v == null) {
         LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         v = vi.inflate(R.layout.fb_friend_list, null);
         holder = new ViewHolder();
         holder.picIV = (ImageView)v.findViewById(R.id.picIV);
         holder.firstNameTV = (TextView)v.findViewById(R.id.firstNameTV);
         holder.lastNameTV = (TextView)v.findViewById(R.id.lastNameTV);
         holder.selectFriendCB = (CheckBox)v.findViewById(R.id.selectFriendCB);
         v.setTag(holder);
         holder.selectFriendCB.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                CheckBox cb = (CheckBox)v;
                FBFriendItem item = (FBFriendItem)cb.getTag();
                item.setSelected(cb.isChecked());
            }
         });
     }
     else {
         holder = (ViewHolder)v.getTag();
     }

     FBFriendItem item = items.get(position);
     holder.picIV.setImageBitmap(item.getImageBitmap());
     holder.firstNameTV.setText(item.getFirstName());
     holder.lastNameTV.setText(item.getLastName());
     holder.selectFriendCB.setChecked(item.isSelected());
     holder.selectFriendCB.setTag(item);

     return v;
 }

 private class ViewHolder {
     ImageView picIV;
     TextView firstNameTV;
     TextView lastNameTV;
     CheckBox selectFriendCB;        
 }

Upvotes: 0

j__m
j__m

Reputation: 9635

The first thing I'm noticing is

     if (!item.getFbId().isEmpty()) {
         firstNameTV.setText(" " + item.getFirstName());
         lastNameTV.setText(" " + item.getLastName());
         Bitmap image = item.getImage();
         if(image != null) {
             picIV.setImageBitmap(image);
         }
     }

Setting these values only in certain cases is a big no-no. Remember that your views are being reused, so if you ever set any of these properties, you can't count on them ever having the default value. They might still be set from the last item. Try logic that looks more like this:

     if (!item.getFbId().isEmpty()) {
         firstNameTV.setText(" " + item.getFirstName());
         lastNameTV.setText(" " + item.getLastName());
         Bitmap image = item.getImage();
         if(image == null) {
             // reset the default because this view might have last displayed an
             // item with a non-default value
             picIV.setImageBitmap(myDefaultImage);
         } else {
             picIV.setImageBitmap(image);
         }
     } else {
         // reset the defaults because this view might have last displayed an
         // item with a non-default value
         firstNameTV.setText(null);
         lastNameTV.setText(null);
         picIV.setImageBitmap(myDefaultImage);
     }

The next thing I'm noticing is that your management of checked items is completely wrong. Whether an item is checked or not is state that should be managed by the ListView, not your adapter. I don't know what look you're trying to achieve, so I'm not going to specify exactly how to lay out your items, but you want to probably start by removing the CheckBox elements and look into ListView.setChoiceMode(). http://developer.android.com/reference/android/widget/AbsListView.html#setChoiceMode%28int%29

Upvotes: 1

Related Questions