ListView Adapter - Multi Selection remove - IndexOutOfBounds

Put your problem here if it does not fit any of the other categories.

ListView Adapter - Multi Selection remove - IndexOutOfBounds

Postby luthepa1 » Tue Jul 24, 2012 2:53 am

I have a custom Listview using a ArrayAdapter of a Item class. I have the ability to change between choice modes of NONE,Single and Multi. This all works fine. What I am trying to implement now is a method to remove items from the list view (and adapter) with single or multiple selections. However I get IndexOutOFBounds Exceptions when doing either of the following;
1) remove last item in listview in SINGLE or MULTI choice mode (Note: anything before last item will remove ok if single item)
2) in multi selection mode I can remove single selected items before last item but 2 or more selections result in index out of bounds errors again.

I added debug log to show position being removed and size of getCheckItemPositions() and my for loop counter (e.g. i) and finally the item title of the item being removed. If I comment out the actual "listadpter.remove(position)" line then the log output seems to indicator all is working fine So I am now suspecting the issue falls into my adapter class getView method. But my brain is exhausted and I am stuck. Below is my code.

MainActivity.class - removeItems method called from a button view object;
Code: Select all
private void removeItems() {
    final SparseBooleanArray checkedItems = listView.getCheckedItemPositions();
    //final long[] checkedItemIds = listView.getCheckedItemIds();
    final int checkedItemsCount = checkedItems.size();

    Log.d("drp", "Adapter Count is: " + Integer.toString(mMyListViewAdapter.getCount()));
    if (checkedItems != null) {
        for (int i = checkedItemsCount-1; i >= 0 ; i--) {
            // This tells us the item position we are looking at
            // --
            final int position = checkedItems.keyAt(i);
            // This tells us the item status at the above position
            // --
            final boolean isChecked = checkedItems.valueAt(i);

            if (isChecked) {
                Item item = mMyListViewAdapter.getItem(position);
                Log.d("drp", "removing : " + Integer.toString(position) + " of " +Integer.toString(checkedItemsCount) + "-" + Integer.toString(i) + " - Title: " + mMyListViewAdapter.getItem(position).getTitle());
                mMyListViewAdapter.remove(item);

            }
        }
    }
}


Adapter Class;
Code: Select all
public class MyListViewAdapter extends ArrayAdapter<Item>  implements OnItemClickListener{

private LayoutInflater mInflator;

/**
* This is my view holder for getView method so don't need to call
* findViewById all the time which results in speed increase
*/
static class ViewHolder {

    public TextView txtTitle;
    public TextView txtDescription;
    public TextView txtSessionCount;
    public ImageView listThumbnailImage;
    public ImageView listStatusIndicatorImage;
    public InertCheckBox Checkbox;
}

/**
* Constructor from a list of items
*/
public MyListViewAdapter(Context context, List<Item> items) {
    super(context, 0, items);
    mInflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // This is how you would determine if this particular item is checked
    // when the view gets created
    // --
    final ListView lv = (ListView) parent;
    final boolean isChecked = lv.isItemChecked(position);
    final int selectionMode = lv.getChoiceMode();

    // The item we want to get the view for
    // --
    Item item = getItem(position);

    // Re-use the view if possible (recycle)
    // --
    ViewHolder holder = null;
    if (convertView == null) {
        convertView = mInflator.inflate(R.layout.listview_row, null);
        holder = new ViewHolder();
        holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
        holder.txtDescription = (TextView) convertView.findViewById(R.id.description);
        holder.txtSessionCount = (TextView) convertView.findViewById(R.id.session_count);
        holder.listThumbnailImage = (ImageView) convertView.findViewById(R.id.list_image);
        holder.listStatusIndicatorImage = (ImageView) convertView.findViewById(R.id.status);
        holder.Checkbox = (InertCheckBox) convertView.findViewById(R.id.inertCheckBox);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }
    holder.txtTitle.setText(item.getTitle());
    holder.txtDescription.setText(item.getDescription());
    holder.txtSessionCount.setText(item.getSessionCount());
    holder.listThumbnailImage.setImageBitmap((Bitmap) item.getThumbnailImage());       
    switch (selectionMode) {
    case ListView.CHOICE_MODE_NONE:
        holder.Checkbox.setVisibility(InertCheckBox.GONE);
        holder.listStatusIndicatorImage.setVisibility(ImageView.VISIBLE);
        holder.listStatusIndicatorImage.setImageBitmap((Bitmap) item.getListIndicatorImage());
        break;
    //case ListView.CHOICE_MODE_SINGLE: case ListView.CHOICE_MODE_MULTIPLE:
    default:
        holder.listStatusIndicatorImage.setVisibility(ImageView.GONE);
        holder.Checkbox.setVisibility(InertCheckBox.VISIBLE);
        holder.Checkbox.setButtonDrawable(R.drawable.checkbox);
        holder.Checkbox.setChecked(isChecked);
        break;
    }           


    return convertView;
}

@Override
public long getItemId(int position) {
    return getItem(position).getId();
}

@Override
public boolean hasStableIds() {
    return true;
}


And Item Class - first half;

Code: Select all
public class Item implements Comparable<Item> {

private long id;
private String title;
private String description;
private String session_count;
private Bitmap listImage;
private Bitmap statusImage;

public Item(long id, String title, String description, String session_count, Bitmap listImage, Bitmap statusImage) {
    super();
    this.id = id;
    this.title = title;
    this.description = description;
    this.session_count = session_count;
    this.listImage = listImage;
    this.statusImage = statusImage;
}

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getTitle() {
    return title;
}


Here is visual of my debug log tracking item removals
07-23 22:59:14.910: D/drp(19104): Adapter Count is: 51
07-23 22:59:14.910: D/drp(19104): removing : 50 of 4-3 - Title: Test 50 - testing
07-23 22:59:14.910: D/drp(19104): removing : 49 of 4-2 - Title: Test 49 - testing
07-23 22:59:14.910: D/drp(19104): removing : 48 of 4-1 - Title: Test 48 - testing


Again if I comment out the "mMyListViewAdapter.remove(item);" line in MainActivity not crashes and log seems to indicated its working as expected. Can anyone see my error that results in my Index Out Of Bounds Exception?

Also I am using SDK 4.0.4 API 15.

Many Thanks,

Paul.
luthepa1
Junior Developer
Junior Developer
 
Posts: 12
Joined: Wed Oct 14, 2009 11:51 pm

Top

Return to Other Coding-Problems

Who is online

Users browsing this forum: No registered users and 9 guests