0

I have a Custom adapter extending BaseAdapter, everything works fine except the returned position of items in the getView method which looks wrong. After the first scroll of the list It gives me the index of the last displayed item.

First scroll top to bottom : 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12

First scroll bottom to top : 12 - 11 - 10 - 9 - 8 - 7 - 6

Second scroll top to bottom : 6 - 7 - 8 - 9 - 10 - 11 - 12

and starts to be pretty random.

This is my Adapter's code :

public abstract class FourComponentsAdapter extends BaseAdapter {

private UIViewImpl context;
private ArrayList<FourComponentsListItem> listItems;
private int layoutId;
private int itemPosition;

public FourComponentsAdapter (Context context, ArrayList<FourComponentsListItem> listItems, int layouId){
    this.context = context;
    this.listItems = listItems;
    this.layoutId = layouId;
}

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

@Override
public Object getItem (int position) {       
    return listItems.get (position);
}

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

@Override
public View getView (int position, View convertView, ViewGroup parent) {

    View rowView = convertView;

    ViewHolder viewHolder;

    if (rowView == null) {
        LayoutInflater inflater = context.getLayoutInflater ();
        rowView = inflater.inflate (layoutId, null);

        viewHolder = new ViewHolder ();

        UIImage thumbnail   = findThumbnail (rowView, viewHolder);
        UILabel title       = findTitle (rowView, viewHolder);
        UILabel subTitle    = findSubTitle (rowView, viewHolder);
        UIIcon actions      = findIconAction (rowView, viewHolder);

        if (thumbnail != null) {
            viewHolder.iconThumbnail = thumbnail;
        }

        if (title != null) {
            viewHolder.title = title;
        }

        if (subTitle != null) {
            viewHolder.subTitle = subTitle;
        }

        if (actions != null) {
            viewHolder.iconAction = actions;
        }

        rowView.setTag (viewHolder);
    } else { 
        viewHolder = (ViewHolder)rowView.getTag ();
    }
    itemPosition = position;

    if (viewHolder.iconThumbnail != null) {
        // Image or text

        viewHolder.iconThumbnail.setOnClickListener (new OnClickListener () {

            @Override
            public void onClick (View view) {
                onThumbnailClick (view, itemPosition);
            }
        });
    } 

    if (viewHolder.title != null) {
        viewHolder.title.setText (listItems.get (position).getTitle ());

        viewHolder.title.setOnClickListener (new OnClickListener () {

            @Override
            public void onClick (View view) {
                onTitleClick (view, itemPosition);
            }
        });
    }

    if (viewHolder.subTitle != null) {
        viewHolder.subTitle.setText (listItems.get (position).getSubTitle ());
    }

    if (viewHolder.iconAction != null) {
        viewHolder.iconAction.setText (listItems.get (position).getIconAction ());
        viewHolder.iconAction.setTag (String.valueOf (position));

        viewHolder.iconAction.setOnClickListener (new OnClickListener () {

            @Override
            public void onClick (View view) {
                onActionClick (view, itemPosition);
            }
        });
    }

    System.out.println ("POSITION ::::: " + itemPosition);

    return rowView;
}

protected abstract UIImage findThumbnail (View rowView, ViewHolder viewHolder);
protected abstract UILabel findTitle (View rowView, ViewHolder viewHolder);
protected abstract UILabel findSubTitle (View rowView, ViewHolder viewHolder);
protected abstract UIIcon findIconAction (View rowView, ViewHolder viewHolder);

protected abstract void onThumbnailClick (View view, int position);
protected abstract void onTitleClick (View view, int position);
protected abstract void onActionClick (View view, int position);

public static class ViewHolder {
    public UIImage iconThumbnail;
    public UILabel title;
    public UILabel subTitle;
    public UIIcon iconAction;
}
}

My Activity's code :

private ArrayList<FourComponentsListItem> listItems = new ArrayList<FourComponentsListItem> (); 

....

UIListView listView = (UIListView) view.findViewById (R.id.list));

listView.setAdapter (
        new FourComponentsAdapter (UserActivityView.this, listItems, listId) {

        @Override
        protected UIImage findThumbnail (View rowView, ViewHolder viewHolder) {
            return (UIImage)rowView.findViewById (R.id.thumbnail);
        }

        @Override
        protected UILabel findTitle (View rowView, ViewHolder viewHolder) {
            return (UILabel)rowView.findViewById (R.id.name);
        }

        @Override
        protected UILabel findSubTitle (View rowView, ViewHolder viewHolder) {
            return (UILabel)rowView.findViewById (R.id.subName);
        }

        @Override
        protected UIIcon findIconAction (View rowView, ViewHolder viewHolder) {
            return (UIIcon)rowView.findViewById (R.id.actions);
        }

        @Override
        protected void onThumbnailClick (View view, int position) {
        }

        @Override
        protected void onTitleClick (View view, int position) {
        }

        @Override
        protected void onActionClick (View view, int position) {

             // Code here
        }
    );

Am I missing something ?? Thank you.

1 Answers1

0

Don't use the variable itemPosition as a class member. To use position inside the onClickListener declare it final.

Furthermore, if you don't use getItem and getItemId, they should return respectively null and 0.

PS: trust the ListView, it knows which view it needs :)

Spotlight
  • 1,279
  • 1
  • 13
  • 28
  • I used the `itemPosition` as a class member to avoid using `final`... I don't really get your point. –  May 15 '14 at 11:20
  • When the ListView calls getView again, itemPosition is overwritten. So, when the OnClickListener is fired, it reads itemPosition, which is equal for each item in your listview (i.e. equal to the position of the last view created by your adapter). – Spotlight May 15 '14 at 11:33
  • Thank you. I know all this.. The reason I have posted here in SO is that I got a non expected behavior which I explained in the question. –  May 15 '14 at 11:35
  • ListView calls getView in an undefined order. You can take a look at the source code, but I suggest to simply trust the ListView implementation. In my experience it simply works. However I find odd the fact that when you scroll bottom to top, getView doesn't get called for the item at position 0. – Spotlight May 15 '14 at 11:50