I have a custom Listview using an adapter class to extend the ArrayAdapter of the Item class. I have the ability to switch between the selection modes NONE, Single and Multi. It all works great. What I'm trying to implement now is a method of removing items from a list (and adapter) with multiple selections in multiple selection mode. However, I get IndexOutOFBounds exceptions when doing any of the following; 1) delete the last element in the list in the SINGLE selection mode (note: anything until the last element is deleted normally) 2) In the multiple-choice mode, I cannot delete the last element again 3) again in the multiple-choice mode. I can delete individual selected items to the last item,but 2 or more choices again lead to index errors outside the bounds.
I added a debug log to show the deleted position and size of getCheckItemPositions () and my loop counter (like i) and finally the title of the element of the deleted element. If I comment on the actual listadpter.remove (position) line, then the log output looks like an indicator, everything works fine. Therefore, I now suspect that the problem falls into my adapter getView method. But my brain is exhausted and I am stuck.
MainActivity.class - the removeItems method called from the button's presentation object;
private void removeItems() {
final SparseBooleanArray checkedItems = listView.getCheckedItemPositions();
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) {
final int position = checkedItems.keyAt(i);
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
public class MyListViewAdapter extends ArrayAdapter<Item> implements OnItemClickListener{
private LayoutInflater mInflator;
static class ViewHolder {
public TextView txtTitle;
public TextView txtDescription;
public TextView txtSessionCount;
public ImageView listThumbnailImage;
public ImageView listStatusIndicatorImage;
public InertCheckBox Checkbox;
}
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) {
final ListView lv = (ListView) parent;
final boolean isChecked = lv.isItemChecked(position);
final int selectionMode = lv.getChoiceMode();
Item item = getItem(position);
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;
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 the element class is the first half;
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 the visual information on deleting debug log tracking items
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
, "mMyListViewAdapter.remove(item);" line MainActivity , , , , , . - , ?
API SDK 4.0.4 API.
,
.
-
07-25 00:21:53.235: D/AbsListView(25952): Get MotionRecognitionManager
07-25 00:21:53.270: D/dalvikvm(25952): GC_CONCURRENT freed 89K, 3% free 13027K/13383K, paused 1ms+2ms
07-25 00:21:53.430: D/dalvikvm(25952): GC_CONCURRENT freed 207K, 4% free 13232K/13703K, paused 3ms+2ms
07-25 00:21:53.630: D/CLIPBOARD(25952): Hide Clipboard dialog at Starting input: finished by someone else... !
07-25 00:21:54.930: D/dalvikvm(25952): GC_FOR_ALLOC freed 189K, 4% free 13331K/13767K, paused 10ms
07-25 00:21:54.930: I/dalvikvm-heap(25952): Grow heap (frag case) to 13.610MB for 408976-byte allocation
07-25 00:21:54.940: D/dalvikvm(25952): GC_FOR_ALLOC freed 6K, 4% free 13724K/14215K, paused 9ms
07-25 00:21:54.950: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 4% free 13724K/14215K, paused 9ms
07-25 00:21:54.950: I/dalvikvm-heap(25952): Grow heap (frag case) to 13.994MB for 408976-byte allocation
07-25 00:21:54.960: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 4% free 14124K/14663K, paused 9ms
07-25 00:21:54.970: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 4% free 14124K/14663K, paused 9ms
07-25 00:21:54.975: I/dalvikvm-heap(25952): Grow heap (frag case) to 14.384MB for 408976-byte allocation
07-25 00:21:54.995: D/dalvikvm(25952): GC_CONCURRENT freed 0K, 4% free 14523K/15111K, paused 1ms+1ms
07-25 00:21:55.005: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 4% free 14523K/15111K, paused 9ms
07-25 00:21:55.005: I/dalvikvm-heap(25952): Grow heap (frag case) to 14.774MB for 408976-byte allocation
07-25 00:21:55.020: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 5% free 14923K/15559K, paused 9ms
07-25 00:21:55.030: D/dalvikvm(25952): GC_FOR_ALLOC freed <1K, 5% free 14923K/15559K, paused 9ms
07-25 00:21:55.030: I/dalvikvm-heap(25952): Grow heap (frag case) to 15.165MB for 408976-byte allocation
07-25 00:21:55.040: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 5% free 15322K/16007K, paused 10ms
07-25 00:21:55.055: D/dalvikvm(25952): GC_FOR_ALLOC freed 0K, 5% free 15722K/16455K, paused 9ms
07-25 00:21:55.110: D/dalvikvm(25952): GC_FOR_ALLOC freed 157K, 5% free 16145K/16903K, paused 9ms
07-25 00:21:56.565: E/SKIA(25952): FimgApiStretch:stretch failed
07-25 00:21:56.690: E/SKIA(25952): FimgApiStretch:stretch failed
07-25 00:21:56.710: E/SKIA(25952): FimgApiStretch:stretch failed
07-25 00:22:00.545: D/drp(25952): Adapter Count is: 51
07-25 00:22:00.545: D/drp(25952): removing : 49 of 2-2 - Title: Test 49 - testing
07-25 00:22:00.545: D/drp(25952): removing : 48 of 2-1 - Title: Test 48 - testing
07-25 00:22:00.545: D/drp(25952): removing : 47 of 2-0 - Title: Test 47 - testing
07-25 00:22:00.550: D/AndroidRuntime(25952): Shutting down VM
07-25 00:22:00.550: W/dalvikvm(25952): threadid=1: thread exiting with uncaught exception (group=0x40c6f1f8)
07-25 00:22:00.560: E/AndroidRuntime(25952): FATAL EXCEPTION: main
07-25 00:22:00.560: E/AndroidRuntime(25952): java.lang.IndexOutOfBoundsException: Invalid index 48, size is 48
07-25 00:22:00.560: E/AndroidRuntime(25952): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
07-25 00:22:00.560: E/AndroidRuntime(25952): at java.util.ArrayList.get(ArrayList.java:304)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.ArrayAdapter.getItem(ArrayAdapter.java:337)
07-25 00:22:00.560: E/AndroidRuntime(25952): at au.drp.mylistview.MyListViewAdapter.getItemId(MyListViewAdapter.java:107)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.AbsListView.confirmCheckedPositionsById(AbsListView.java:5956)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.AbsListView.handleDataChanged(AbsListView.java:5999)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.ListView.layoutChildren(ListView.java:1535)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.AbsListView.onLayout(AbsListView.java:2254)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.RelativeLayout.onLayout(RelativeLayout.java:925)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1644)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1502)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.LinearLayout.onLayout(LinearLayout.java:1415)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.View.layout(View.java:11467)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewGroup.layout(ViewGroup.java:4237)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1721)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2678)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.os.Handler.dispatchMessage(Handler.java:99)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.os.Looper.loop(Looper.java:137)
07-25 00:22:00.560: E/AndroidRuntime(25952): at android.app.ActivityThread.main(ActivityThread.java:4514)
07-25 00:22:00.560: E/AndroidRuntime(25952): at java.lang.reflect.Method.invokeNative(Native Method)
07-25 00:22:00.560: E/AndroidRuntime(25952): at java.lang.reflect.Method.invoke(Method.java:511)
07-25 00:22:00.560: E/AndroidRuntime(25952): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
07-25 00:22:00.560: E/AndroidRuntime(25952): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)