bad convertView type BaseAdapter of ListView
Asked Answered
W

4

9

I have a list view adapter that uses different types of view rows.

Most of the time it works fine. But when I remove an element from the list it crashes. It sends a convertView of the incorrect type to getView

public View getView(int position, View convertView, ViewGroup patent) ...  

But getItemViewType is returning the correct type.

public int getItemViewType(int position)

so I see something that looks like this

give me the type for position 1 -> returns correct type (say 1)

give me a view for position 1 with a content view for the wrong type (say type 2.)

Any ideas?

Walloping answered 8/12, 2011 at 18:46 Comment(1)
post your getView() and getItemViewType()Volitive
C
1

That's normal, if you get a View with different type in convertView, you would create a new View, and not reuse convertView.

Probably there are no reusable views with the given type.

Note: This answer is from 2011 and might no longer apply.

Christman answered 21/12, 2011 at 3:18 Comment(6)
there is a recycler that holds the views. if it's the wrong kind you can leak if you don't use it.Walloping
The recycler will test if the View you return from #getView(int, View, ViewGroup) is the convertView - if it is not the convertView will be placed back in the recycler for reuse or scrapping later on. Basically - it shouldn't leak (and doesn't afaik) - so Varga Péter is correct.Ferroconcrete
I no longer think this is the answer. See this post that says to always use the content view. groups.google.com/group/android-developers/browse_thread/thread/…Walloping
Fair enough (you mean convert view in the question and in your comment too right?), but frankly, the Android library is full of these little bugs so I was just assuming this is yet another case... But the solution is either a) don't use the convertView, at worst you "leak" it, which at worst means as many Views leaked as are removed from the list, which I guess is a user initiated action... b) delve into the Android BaseAdapter implementation and fix this bug, and then ask every user to upgrade their phone(???) c) write your own ListView clone which doesn't leak.Christman
ListView works pretty well and the developers paid close attention to the recycler. The 'answer' is just full of assumptions, backed by no concrete reference to code. @Santhosh's answer will fix the issue encounteredGrano
Yeah well, I don't do Android coding for some time but bear in mind the question is from 2011. We definitely had issues with ListView, but perhaps just due to not implementing getViewTypeCount. Perhaps recent SDKs include a fixed ListView.Christman
I
20

Try overiding getViewTypeCount()

@Override
public int getViewTypeCount() {
       return types;
}

Return the number of types of Views that will be created by getView(int, View, ViewGroup). Each type represents a set of views that can be converted in getView(int, View, ViewGroup).

Isopod answered 27/12, 2011 at 8:33 Comment(4)
Pay attention to this answer! It is something that solved my problem with wrong view type of convertedView. Now convertedView is either of correct view type or null.Metic
In my case I made sure I implemented this, but after that I copy-pasted some methods and accidentally deleted it. Thanks for pinpointing.Buyer
This answer does not address the problem on its own, at least not on Android 4.4.2. getView will still sometimes get the wrong kind of convertView.Burnsides
Nevermind, this answer is fine. I was seeing the wrong type of view passed as convertView because I was overwriting the AbsListView.LayoutParams variable of the view. That is where the recycler looks when determining where to save a removed view (AbsListView.LayoutParams.viewType).Burnsides
T
3

When implemented right, the ListView guarantees that the view provided as the convertView is from the right Type

     /**
     * @return A view from the ScrapViews collection. These are unordered.
     */
    View getScrapView(int position) {
        if (mViewTypeCount == 1) {
            return retrieveFromScrap(mCurrentScrap, position);
        } else {
            int whichScrap = mAdapter.getItemViewType(position);
            if (whichScrap >= 0 && whichScrap < mScrapViews.length) {
                return retrieveFromScrap(mScrapViews[whichScrap], position);
            }
        }
        return null;
    }

You should override getViewTypeCount(), returning the number of view types you have and override getItemViewType(int position) returning the view type in the range from 0 to getViewTypeCount() - 1

Tackett answered 8/10, 2013 at 2:49 Comment(1)
This isn't entirely correct. In pre-JellyBean builds, when the Adapter's dataset changes, causing a reordering of Views, getViewType() will still return correctly for each row, but the convertView supplied to that row can be of the wrong type. You need to check the convertView's type in getView().Persas
C
1

That's normal, if you get a View with different type in convertView, you would create a new View, and not reuse convertView.

Probably there are no reusable views with the given type.

Note: This answer is from 2011 and might no longer apply.

Christman answered 21/12, 2011 at 3:18 Comment(6)
there is a recycler that holds the views. if it's the wrong kind you can leak if you don't use it.Walloping
The recycler will test if the View you return from #getView(int, View, ViewGroup) is the convertView - if it is not the convertView will be placed back in the recycler for reuse or scrapping later on. Basically - it shouldn't leak (and doesn't afaik) - so Varga Péter is correct.Ferroconcrete
I no longer think this is the answer. See this post that says to always use the content view. groups.google.com/group/android-developers/browse_thread/thread/…Walloping
Fair enough (you mean convert view in the question and in your comment too right?), but frankly, the Android library is full of these little bugs so I was just assuming this is yet another case... But the solution is either a) don't use the convertView, at worst you "leak" it, which at worst means as many Views leaked as are removed from the list, which I guess is a user initiated action... b) delve into the Android BaseAdapter implementation and fix this bug, and then ask every user to upgrade their phone(???) c) write your own ListView clone which doesn't leak.Christman
ListView works pretty well and the developers paid close attention to the recycler. The 'answer' is just full of assumptions, backed by no concrete reference to code. @Santhosh's answer will fix the issue encounteredGrano
Yeah well, I don't do Android coding for some time but bear in mind the question is from 2011. We definitely had issues with ListView, but perhaps just due to not implementing getViewTypeCount. Perhaps recent SDKs include a fixed ListView.Christman
H
1

I had the same issue and it resulted in crashes or unexpected behavior.
This how I fixed my issue:

    getViewTypeCount() should return the number of different type of rows in the view
    getItemViewType(...) should return the type of the item at position
    getView(...) should set a enum type on view when inflated
@Override
public int getViewTypeCount() {
    return 2;
}

@Override
public int getItemViewType(int position) {
    return mlistItems.get(position).type.ordinal();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ListItem item = mListems.get(position);

    if (convertView == null) {
        switch (item.type) {
            case Header:
                converview = // Inflate Header Row
                break;
            case Content:
                converview = // Inflate Content Row
                break;
        }
    }

    switch (item.type) {
            case Header:
                //Set header row content
                break;
            case Content:
                //Set content row content
                break;
    }

    return convertView;
}
Hole answered 16/3, 2016 at 19:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.