ArrayIndexOutOfBoundsException con adaptador de Android personalizado para múltiples vistas en ListView

185

Estoy intentando crear un Adaptador personalizado para mi ListView, ya que cada elemento de la lista puede tener una vista diferente (un enlace, alternar o grupo de radio), pero cuando intento ejecutar la Actividad que usa ListView, recibo un error y La aplicación se detiene. La aplicación está dirigida a la plataforma Android 1.6.

El código:

public class MenuListAdapter extends BaseAdapter {
 private static final String LOG_KEY = MenuListAdapter.class.getSimpleName();

 protected List<MenuItem> list;
 protected Context ctx;
 protected LayoutInflater inflater;

 public MenuListAdapter(Context context, List<MenuItem> objects) {
  this.list = objects;
  this.ctx = context;
  this.inflater = (LayoutInflater)this.ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  Log.i(LOG_KEY, "Position: " + position + "; convertView = " + convertView + "; parent=" + parent);
  MenuItem item = list.get(position);
  Log.i(LOG_KEY, "Item=" + item );

        if (convertView == null)  {
            convertView = this.inflater.inflate(item.getLayout(), null);
        }

        return convertView;
 }

 @Override
 public boolean areAllItemsEnabled() {
  return false;
 }

 @Override
 public boolean isEnabled(int position) {
  return true;
 }

 @Override
 public int getCount() {
  return this.list.size();
 }

 @Override
 public MenuItem getItem(int position) {
  return this.list.get(position);
 }

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

 @Override
 public int getItemViewType(int position) {
  Log.i(LOG_KEY, "getItemViewType: " + this.list.get(position).getLayout());
  return this.list.get(position).getLayout();
 }

 @Override
 public int getViewTypeCount() {
  Log.i(LOG_KEY, "getViewTypeCount: " + this.list.size());
  return this.list.size();
 }

}

El error que recibo:

    java.lang.ArrayIndexOutOfBoundsException
  at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:3523)
  at android.widget.ListView.measureHeightOfChildren(ListView.java:1158)
  at android.widget.ListView.onMeasure(ListView.java:1060)
  at android.view.View.measure(View.java:7703)

Sé que la aplicación está regresando getViewy todo parece estar en orden.

Cualquier idea sobre lo que podría estar causando esto sería apreciada.

Gracias,

-Dan

Dan
fuente
Hola Dan, ¿estás seguro de que getCount tiene el total de elementos que se mostrarán en tu ListView? public int getCount () {return this.list.size (); }
Jorgesys
44
No pudieron encontrar un mensaje de error menos descriptivo ...
JoeyJ

Respuestas:

515

El tipo de vista del elemento desde el que regresa

getItemViewType()es >= getViewTypeCount().

Romain Guy
fuente
24
Este es desagradable. No hay forma de depurarlo. Muchas gracias, Romain Guy por explicarlo.
Yar
113
Otra cosa es que ViewType debe comenzar desde 0.
HelmiB
16
Recibió 38 votos a favor para la respuesta hasta ahora, por lo que esta puede ser una respuesta perfecta, pero agregue más texto para explicar el problema y cómo resolverlo ... porque todavía no puedo entender mucho de esto.
Chirag Patel
15
Para aquellos que están perplejos, ViewType debe devolver un índice basado en cero. por ejemplo (0, 1, 2 ...). en mi caso intenté reutilizar R.layout ... para ViewType. Supongo que internamente el valor de ViewType se está utilizando como índice para el grupo de reciclaje y no como una clave.
Samuel
2
Gracias por explicar este error, a diferencia de los desarrolladores de Android que, como de costumbre, no se molestaron en mencionar este título vital en su documentación.
WKS
17

La respuesta aceptada es correcta. Esto es lo que estoy haciendo para evitar el problema:

public enum FoodRowType {
    ONLY_ELEM,
    FIRST_ELEM,
    MID_ELEM,
    LAST_ELEM
}

@Override
public int getViewTypeCount() {
    return FoodRowType.values().length;
}

@Override
public int getItemViewType(int position) {
    return rows.get(position).getViewType();  //returns one of the above types
}
mtbomb
fuente
Podría ser agradable solo si getItemViewTypeno volviera int
dVaffection
0

El problema surge cuando el valor de getItemType es incorrecto. Este valor debe ser un entero y debe ser de 0 para getViewTypeCount () - 1.

sunil jain
fuente
-3

La razón es muy probable porque el método getItemViewType está devolviendo los valores incorrectos. Cada fila en la vista de lista es una vista. Mientras explora getItemViewType alcanza más que el recuento de vistas.

¿Qué hacer? ¿Cómo evitar problemas?

Primero determine la vista (fila) en su vista de lista que se muestra primero. Mientras se desplaza use la ecuación del modulador

    @Override
    public int getItemViewType(int position) {
        return choseType(position);//function to use modular equation
    }
    @Override
    public int getViewTypeCount() {
        return 10;
    }

En este ejemplo, hay diez vistas (10 filas).

private  int choseType(int position){
    if(position%10==0)
        return 0;
    else if(position%10==1)
        return 1;
    else if(position%10==2)
        return 2;
    else if(position%10==3)
        return 3;
    else if(position%10==4)
        return 4;
    else if(position%10==5)
        return 5;
    else if(position%10==6)
        return 6;
    else if(position%10==7)
        return 7;
    else if(position%10==8)
        return 8;
    else
        return 9;


}

Importante

Algunos usuarios mencionaron en otra pregunta sobre stackoverflow ese método

public int getViewTypeCount () y public int getItemViewType (int position) arreglan como el botón Toogle automáticamente habilitan la verificación de estado verdadero en el scrooling ... eso es un gran error . Si no desea el enbale automático en scrool, simplemente haga

toogleButton.setChecked(false);

en el método de anulación getView.

Beyaz
fuente