ArrayIndexOutOfBoundsException com adaptador Android personalizado para várias visualizações no ListView

185

Estou tentando criar um adaptador personalizado para o meu ListView, pois cada item da lista pode ter uma exibição diferente (um link, alternância ou grupo de rádio), mas quando tento executar a Atividade que usa o ListView, recebo um erro e o aplicativo para. O aplicativo é direcionado para a plataforma Android 1.6.

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

}

O erro que recebo:

    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)

Eu sei que o aplicativo está retornando getViewe tudo parece estar em ordem.

Qualquer idéia sobre o que poderia estar causando isso seria apreciada.

Obrigado,

-Dan

Dan
fonte
Oi Dan, você tem certeza que o getCount tem o total de elementos para serem exibidos no seu ListView ??? public int getCount () {retorne this.list.size (); }
Jorgesys 07/04
4
Eles não poderia vir acima com uma mensagem de erro menos descritiva ...
JoeyJ

Respostas:

515

O tipo de exibição do item do qual você está retornando

getItemViewType()é >= getViewTypeCount().

Romain Guy
fonte
24
Este é desagradável. Não há como depurar. Muito obrigado, Romain Guy, por explicar isso.
Yar
113
outra coisa é, ViewType deve começar a partir 0.
HelmiB
16
Você tem 38 votos positivos para a resposta até agora, portanto esta pode ser uma resposta perfeita, mas adicione mais texto para explicar o problema e como resolvê-lo ... porque ainda não consigo entender muito disso.
amigos estão
15
Para aqueles que estão perplexos, o ViewType deve retornar um índice baseado em zero. por exemplo (0, 1, 2 ...). no meu caso, tentei reutilizar o R.layout ... para o ViewType. Eu acho que internamente o valor do ViewType está sendo usado como índice para reciclagem de pool e não como chave.
Samuel
2
Obrigado por explicar esse erro, diferentemente dos desenvolvedores do Android que, como sempre, não se incomodaram em mencionar esse detalhe vital em sua documentação.
WKS
17

A resposta aceita está correta. Isto é o que estou fazendo para evitar o 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
fonte
Poderia ser bom se getItemViewTypenão fosse para int retorno
dVaffection
0

Problema ocorre quando o valor getItemType está errado. Este valor deve ser um número inteiro e deve ser de 0 a getViewTypeCount () - 1.

sunil jain
fonte
-3

O motivo é mais provável porque o método getItemViewType está retornando os valores incorretos! Cada linha na visualização de lista é uma visualização. Enquanto o rastreamento de getItemViewType atinge mais do que a contagem de visualizações.

O que fazer? Como evitar problemas?

Primeiro, determine a exibição (linha) em sua exibição de lista que é mostrada primeiro. Enquanto a rolagem usa a equação do modulador

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

Neste exemplo, há dez visualizações (10 linhas).

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

Alguns usuários mencionaram em outra pergunta no stackoverflow esse método

public int getViewTypeCount () e public int getItemViewType (int position) corrigem como o Tooglebutton habilitam automaticamente a verificação de estado verdadeira ao arrastar .. isso é muito errado .

toogleButton.setChecked(false);

no método de substituição getView.

Beyaz
fonte