ArrayIndexOutOfBoundsException avec adaptateur Android personnalisé pour plusieurs vues dans ListView

185

J'essaie de créer un adaptateur personnalisé pour ma ListView car chaque élément de la liste peut avoir une vue différente (un lien, une bascule ou un groupe de radio), mais lorsque j'essaie d'exécuter l'activité qui utilise ListView, je reçois une erreur et l'application s'arrête. L'application est destinée à la plate-forme Android 1.6.

Le code:

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

}

L'erreur que je reçois:

    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)

Je sais que l'application revient getViewet que tout semble en ordre.

Toute idée sur ce qui pourrait en être la cause serait appréciée.

Merci,

-Dan

Dan
la source
Salut Dan, êtes-vous sûr que getCount a le total des éléments à afficher sur votre ListView ??? public int getCount () {retourne this.list.size (); }
Jorgesys
4
Ils ne pouvaient pas trouver un message d'erreur moins descriptif ...
JoeyJ

Réponses:

515

Le type de vue d'élément dont vous retournez

getItemViewType()est >= getViewTypeCount().

Romain Guy
la source
24
Celui-ci est méchant. Aucun moyen de le déboguer. Merci beaucoup, Romain Guy de l'expliquer.
Yar le
113
une autre chose est que ViewType doit commencer à partir de 0.
HelmiB
16
Vous avez eu 38 votes positifs pour la réponse jusqu'à présent, donc cela peut être une réponse parfaite, mais veuillez ajouter un texte supplémentaire pour expliquer le problème et comment le résoudre ... parce que je ne comprends toujours pas grand-chose de cela.
Chirag Patel
15
Pour ceux qui sont perplexes, le ViewType doit renvoyer un index de base zéro. par exemple (0, 1, 2 ...). dans mon cas, j'ai essayé de réutiliser le R.layout ... pour le ViewType. Je suppose qu'en interne la valeur de ViewType est utilisée comme index pour le pool de recyclage et non comme clé.
Samuel
2
Merci d'avoir expliqué cette erreur contrairement aux développeurs Android qui, comme d'habitude, ne pouvaient pas se donner la peine de mentionner ce point vital dans leur documentation.
WKS
17

La réponse acceptée est correcte. Voici ce que je fais pour éviter le problème:

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
la source
Cela pourrait être bien seulement si getItemViewType
je
0

Le problème survient lorsque la valeur de getItemType est incorrecte. Cette valeur doit être un entier et doit être comprise entre 0 et getViewTypeCount () - 1.

sunil jain
la source
-3

La raison est probablement parce que la méthode getItemViewType renvoie les mauvaises valeurs! Chaque ligne de la liste est une vue unique. Lors du balayage, getItemViewType atteint plus que le nombre de View.

Que faire? Comment éviter les problèmes?

Déterminez d'abord la vue (ligne) de votre liste qui s'affiche en premier. Pendant le défilement, utilisez l'équation du modulateur

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

Dans cet exemple, il y a dix vues (10 lignes).

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;


}

Important

Certains utilisateurs ont mentionné sur une autre question sur stackoverflow cette méthode

public int getViewTypeCount () et public int getItemViewType (int position) corrigent comme Tooglebutton activer automatiquement la vérification d'état true lors du balayage .. c'est gros faux . Si vous ne voulez pas d'enbale automatique sur le balayage, faites

toogleButton.setChecked(false);

sur la méthode de remplacement getView.

Beyaz
la source