Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BaseAdapter returns wrong position on getView() method call

Strangely enough my CustomBaseAdapter is returning wrong position for the item that needs to be inflated and so on the adapter takes the wrong kind of data to display on the row!

Although i am using the ViewHolder pattern, my ListView layout_height is set to match_parent and every possible way i have found, to ensure ListView items stability, is already implemented, the CustomBaseAdapter seems not to be responding at it.

getView() method

@Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;
        mItemView = convertView;
        if (convertView == null) {
            mItemView = mInflater.inflate(R.layout.layout_listview_row, parent, false);
            holder = new ViewHolder();
            //setting up the Views
            mItemView.setTag(holder);
        } else {
            holder = (ViewHolder) mItemView.getTag();
        }

        //Getting the item
        final MyItem item = getItem(position);

        //Doing some checks on my item and then display the appropriate data.

        //By saying checks i mean something like: 

        if(item.getSomething().equals("blabla")){
           //Load some pic
        }else{
           //Load another pic
        }
        //Now when i have scrolled the list once and return back to top,
        //Suddenly in Logcat i am seeing that the first row is getting matched to
        //the object in the 4th position, but it doesnt display its data. It displays
        //the text from the first item as it was supposed to do. But the relation between
        //the first row and the item's position is like 0->4. 
}

Other methods

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

@Override
public MyItem getItem(int position) {
    return this.mObjects.get(position);
}

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

I have literally searched and tried everything on Google! Nothing seems to have given me a solution.

Any help would be appreciated! Let me know if you need any more part of code.

like image 892
Pavlos Avatar asked Oct 19 '22 21:10

Pavlos


2 Answers

You are "recycling" the display objects, but you are responsible for getting the proper data into them. The issue is this line of code:

    mItemView = convertView;

convertView is the "container" for your data. If convertView is not null, then the container is constructed, but you must then put the appropriate data into it. This is typically done by "using" the position indicator.

Maybe like this:

    if (convertView == null) {
        mItemView = mInflater.inflate(R.layout.layout_listview_row, parent, false);
        holder = new ViewHolder();
        //setting up the Views
        mItemView.setTag(holder);
    } else {
        holder = getItem(position);
        mItemView.setTag(holder);
    }
like image 182
Jim Avatar answered Oct 22 '22 11:10

Jim


I suspect that mItemView is the culprit here. Judging by the name, this is an instance field, so if more than one thread calls getView() in your CustomBaseAdapter, then mItemView may change which recycled view it is pointing at right under your nose. Also, I assume that getView() ends with a return mItemView, right?

Anyway, I would advise to try eliminating mItemView and just write the function like this:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.layout_listview_row, parent, false);
        ViewHolder holder = new ViewHolder();
        //setting up the Views
        convertView.setTag(holder);
    }

    ViewHolder holder = (ViewHolder) convertView.getTag();

    // ...

    return convertView;
}
like image 44
Giorgos Kylafas Avatar answered Oct 22 '22 10:10

Giorgos Kylafas