185

I am attempting to create a custom Adapter for my ListView since each item in the list can have a different view (a link, toggle, or radio group), but when I try to run the Activity that uses the ListView I receive an error and the app stops. The application is targeted for the Android 1.6 platform.

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

}

The error I receive:

    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)

I do know that the application is returning from getView and everything seems in order.

Any ideas on what could be causing this would be appreciated.

Thanks,

-Dan

Anthony Forloney
  • 90,123
  • 14
  • 117
  • 115
Dan
  • 3,884
  • 3
  • 27
  • 32
  • Hi Dan, are you sure getCount have the total of elementsto be displayed on your ListView??? public int getCount() { return this.list.size(); } – Jorgesys Apr 07 '10 at 23:45
  • 4
    They couldn't come up with a less descriptive error message... – JoeyJ Mar 05 '12 at 21:45

4 Answers4

514

The item view type you are returning from

getItemViewType() is >= getViewTypeCount().

Vikalp Patel
  • 10,669
  • 6
  • 61
  • 96
Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • Perfect! I didn't realize the ItemViewType was meant to be a value "local" to the adapter, not the id of the view. – Dan Apr 08 '10 at 12:15
  • 114
    another thing is, ViewType must start from 0. – HelmiB Oct 03 '11 at 03:22
  • 16
    You got 38 upvote for the answer till now so this may be a perfect answer,but please add some more text for explaining the problem and how to resolve it..cause I still cant understand much from this. – Chirag Patel Apr 24 '12 at 11:39
  • 15
    For those who are stumped, the ViewType must return a zero based index . eg (0, 1, 2...). in my case i tried to reuse the R.layout... for the ViewType. i guess internally the ViewType's value is being used as the index for recycling pool and not as a key. – Samuel May 11 '12 at 05:00
  • Thank you, this would have taken me days to find. Also, if your getViewTypeCount() ever needs to change, you need to call getListView.setAdapter(this.adapter) again because getViewTypeCount() is ONLY called when the adapter is first set. – Kenny Wyland Aug 21 '17 at 02:14
17

The accepted answer is correct. This is what I am doing to avoid the problem:

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
  • 1,107
  • 1
  • 13
  • 16
0

Issue comes when getItemType value is wrong. This value should be an integer and should be from 0 to getViewTypeCount()-1.

sunil jain
  • 91
  • 2
-3

The reason, is most likely because the getItemViewType method is returning the wrong values! Each row in listview is a one View. While scrooling getItemViewType reach more than View's count.

What to do? How to avoid issue?

First determine view(row) in your listview that is shown first.While Scrolling use moduler equation

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

In this example there is ten view(10 row).

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

Some users mentioned on another question on stackoverflow that method

public int getViewTypeCount() and public int getItemViewType(int position) fix like Tooglebutton automaticly enable state check true on scrooling..that is big wrong .If you dont want automatic enbale on scrool just do

toogleButton.setChecked(false);

on getView override method.

Beyaz
  • 138
  • 1
  • 13