Android - Adaptador de ListView personalizado - Selección múltiple eliminar - Indexoutofbounds - ¿por qué?

Tengo una vista de lista personalizada que utiliza una clase de adaptador para extender ArrayAdapter de una clase de elemento. Tengo la capacidad de cambiar entre los modos de elección de NINGUNO, Único y Múltiple. Todo esto funciona bien. Lo que estoy tratando de implementar ahora es un método para eliminar elementos de la vista de lista (y el adaptador) con selección múltiple en el modo de selección múltiple. Sin embargo, obtengo excepciones de IndexOutOFBounds cuando hago cualquiera de las siguientes acciones; 1) eliminar el último elemento en la vista de lista en SINGLE modo de elección (Nota: cualquier cosa antes del último elemento eliminar ok) 2) En el modo de selección múltiple, una vez más no puedo eliminar el último elemento 3) nuevamente en el modo de selección múltiple puedo eliminar elementos individuales seleccionados antes el último elemento, pero 2 o más selecciones dan como resultado errores de índice fuera de límites nuevamente.

Agregué el registro de depuración para mostrar la posición que se está eliminando y el tamaño de getCheckItemPositions () y mi contador de bucles for (por ejemplo, i) y, finalmente, el título del elemento que se está eliminando. Si comento la línea real listadpter.remove (posición), el resultado del registro parece indicar que todo está funcionando bien, por lo que ahora sospecho que el problema se encuentra en el método getView de mi clase de adaptador. Pero mi cerebro está agotado y estoy atascado.

MainActivity.class - método removeItems llamado desde un objeto de vista de botón;

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);

            }
        }
    }
}

Clase de adaptador;

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;
}

Y Clase de Objetos - primera mitad;

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;
}

Aquí es visual de mi eliminación de elementos de seguimiento de registro de depuración

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

De nuevo, si comento el "mMyListViewAdapter.remove (item)"; la línea en MainActivity no se bloquea y el registro parece indicar que funciona como se esperaba. ¿Alguien puede ver mi error que resulta en mi Excepción de índice fuera de límites?

También estoy usando SDK 4.0.4 API 15.

Muchas gracias,

Pablo.

Adición - salida de registro completo

        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)

Respuestas a la pregunta(6)

Su respuesta a la pregunta