Reputation: 51
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
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
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